У меня есть постоянно работающее консольное приложение .Net Core (2.1), которое планирует ряд повторяющихся фоновых задач с помощью планировщика Quartz.Net. Я пытаюсь запустить приложение на сервере Linux (16.04). Приложение работает нормально при работе в качестве отдельного приложения. Однако, когда я пытаюсь запустить приложение как службу systemd, оно зависает. Приложение загружает и планирует различные задачи в Quartz.Net, но запланированные фоновые задачи никогда не выполняются. Чем отличается выполнение службы от автономной?
Конфигурационный файл службы systemd выглядит следующим образом:
[Unit]
Description=FiddleMon.Background
[Service]
User=ubuntu
Restart=on-failure
ExecStart=/home/ubuntu/scripts/start-fiddlemon.background.sh
[Install]
WantedBy=multi-user.target
Я не знаю, имеет ли это какое-либо отношение к ситуации, но я заметил разницу в столбце STAT из списка ps aux для приложения в зависимости от того, работает ли оно автономно или как служба (SLl против SLl +):
standalone => 1782 1.4 8.4 2923228 171996 pts/1 SLl+ 00:18 0:33 /usr/bin/dotnet FiddleMon.Background.dll
service => 1518 8.9 4.7 2767936 97132 ? SLl 23:59 0:03 /usr/bin/dotnet FiddleMon.Background.dll
Мы ценим любые предложения.
Можете ли вы поделиться содержимым start-fiddlemon.background.sh?
+ в ps означает, что это группа процессов переднего плана, в основном процесс, который получает сигналы, если вы нажимаете Ctrl-C. Не кажется актуальным. Можете ли вы включить отладку (добавить set -x в файл .sh) и опубликовать вывод journalctl -u $SERVICE_NAME?
@MarkoLahma Спасибо за ваш комментарий, см. Ответ ниже.
@omajid Спасибо за ваш комментарий, см. ответ ниже.
Для меня ReadLine блокирует поток. Наверное, не связано, но я запускаю dll напрямую: ExecStart=/bin/dotnet/dotnet Service.dll





Я наконец понял, что происходит. Исходная структура метода Main в Program.cs была следующей ниже. Этот код отлично работал при запуске в Windows и Linux как отдельный процесс, связанный с сеансом терминала. В Linux, как только завершается сеанс терминала, фоновая программа завершается, как и основной поток программы.
Когда программа запускалась как служба Linux, с программой не было связанного сеанса терминала, поэтому Console.ReadLine() не приводил к блокировке потока, и программа немедленно завершалась. Решением было заменить Console.ReadLine() некоторым кодом, который заставил бы поток блокироваться и оставаться в живых, чтобы могли выполняться фоновые потоки, управляемые Quartz.Net. Есть много разных способов сделать это, и на StackOverflow ведутся многочисленные дискуссии о «лучшем» способе сделать это. Моим простым решением было заменить Console.ReadLine на Thread.Sleep(Timeout.Infinite). Это заставляет основной поток блокироваться и оставаться в живых навсегда. Обратите внимание, что с помощью этого решения, если вы хотите иметь возможность вручную завершить программу, должен быть способ сделать это за пределами основного потока, поскольку он спит вечно.
**Original Code**
static void Main(string[] args)
{
_scheduler = InitializeQuartzScheduler();
_scheduler.ScheduleBackgroundJob<BackgroundJob1>(Yesterday.At(1, 30).AsPstToUtc(), 1.Hours());
_scheduler.ScheduleBackgroundJob<BackgroundJob2>(Yesterday.At(0, 10, 30).AsPstToUtc(), 10.Minutes());
...
_scheduler.ScheduleBackgroundJob<BackgroundJob7>(Yesterday.At(1, 45).AsPstToUtc(), 8.Hours());
_scheduler.ScheduleBackgroundJob<BackgroundJob8>(Yesterday.At(0, 10).AsPstToUtc(), 6.Hours());
Console.Readline();
}
Как вы планируете задания, если из файла может быть разница в рабочем каталоге или разрешениях?