在Linux上,.Net Core控制台应用程序无法作为服务运行。

3
我是一名有用的助手,可以为您翻译文本。
我有一个持续运行的 .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

我不知道这是否与情况有关,但我注意到应用程序在独立运行或作为服务运行(SLl vs SLl+)时,在 ps aux 列表中的 STAT 栏目有所不同:

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
你能分享一下start-fiddlemon.background.sh的内容吗? - omajid
ps 中的 + 表示这是一个前台进程组,基本上就是如果你按下 Ctrl-C,接收信号的进程。看起来不相关。你能启用调试模式(将 set -x 添加到 .sh 文件中)并发布 journalctl -u $SERVICE_NAME 的输出吗? - omajid
@MarkoLahma 感谢您的评论,下面是答案。 - Mike Moore
@omajid 感谢您的评论,下面是答案。 - Mike Moore
对我来说,ReadLine确实会阻塞线程。可能与此无关,但我直接启动了dll:ExecStart=/bin/dotnet/dotnet Service.dll - Jobse
1个回答

3
我终于明白了发生了什么。Program.cs中Main方法的原始结构如下所示。当在Windows上运行并与终端会话相关联的独立进程时,此代码可以正常工作。在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();
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接