Reputation: 1340
I have a continuously running .Net Core (2.1) console app that schedules a number of repeating background tasks using the Quartz.Net scheduler. I am attempting to run the app on a Linux server (16.04). The app runs fine when running as a standalone application. However, when I try to run the app as a systemd service it hangs. The app loads and schedules the various tasks in Quartz.Net, but the scheduled background tasks never execute. What is different about the execution of a service versus standalone?
The systemd service config file is as follows:
[Unit]
Description=FiddleMon.Background
[Service]
User=ubuntu
Restart=on-failure
ExecStart=/home/ubuntu/scripts/start-fiddlemon.background.sh
[Install]
WantedBy=multi-user.target
I don't know if this has anything to do with the situation, but I did notice a difference in the STAT column from the ps aux
listing for the app depending on whether it is running standalone or as a service (SLl vs 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
Any suggestions would be appreciated.
Upvotes: 3
Views: 2022
Reputation: 1340
I finally figured out was was going on. The original structure of the Main method in Program.cs was as follows below. This code worked fine when running on Windows and on Linux as a standalone process that was associated with a terminal session. On Linux as soon as the terminal session was terminated the background program would terminate as the main program thread would be terminated as well.
When the program was run as a Linux service there was no terminal session associated with the program so Console.ReadLine()
would not cause the thread to block and the program would immediately terminate. The solution was to replace Console.ReadLine()
with some code that would cause the thread to block and stay alive so that the background threads managed by Quartz.Net could execute. There are a lot of different ways that this can be accomplished and there are numerous StackOverflow discussions regarding the "best" way to do this. My simple solution was to replace Console.ReadLine
with Thread.Sleep(Timeout.Infinite)
. This causes the main thread to block and stay alive forever. Note that with this solution if you want to be able to manually terminate the program there needs to be a way to do it outside of the main thread as it is asleep forever.
**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();
}
Upvotes: 4