Консольное приложение .Net Core в Linux не будет работать как служба

У меня есть постоянно работающее консольное приложение .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  

Мы ценим любые предложения.

Как вы планируете задания, если из файла может быть разница в рабочем каталоге или разрешениях?

Marko Lahma 05.07.2018 09:04

Можете ли вы поделиться содержимым start-fiddlemon.background.sh?

omajid 05.07.2018 15:24

+ в ps означает, что это группа процессов переднего плана, в основном процесс, который получает сигналы, если вы нажимаете Ctrl-C. Не кажется актуальным. Можете ли вы включить отладку (добавить set -x в файл .sh) и опубликовать вывод journalctl -u $SERVICE_NAME?

omajid 05.07.2018 15:34

@MarkoLahma Спасибо за ваш комментарий, см. Ответ ниже.

Mike Moore 05.07.2018 22:31

@omajid Спасибо за ваш комментарий, см. ответ ниже.

Mike Moore 05.07.2018 22:32

Для меня ReadLine блокирует поток. Наверное, не связано, но я запускаю dll напрямую: ExecStart=/bin/dotnet/dotnet Service.dll

Jobse 24.12.2018 21:40
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
6
1 249
1

Ответы 1

Я наконец понял, что происходит. Исходная структура метода 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();
    }

Другие вопросы по теме