【问题标题】:.Net Core console app on Linux will not run as serviceLinux 上的 .Net Core 控制台应用程序不会作为服务运行
【发布时间】:2018-12-11 07:43:30
【问题描述】:

我有一个持续运行的 .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

我不知道这是否与这种情况有关,但我确实注意到应用程序的 ps aux 列表中的 STAT 列有所不同,具体取决于它是独立运行还是作为服务运行(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 中的+ 表示这是一个foreground process group,基本上就是当你点击Ctrl-C 时获取信号的过程。似乎不相关。能否启用调试(将set -x 添加到.sh 文件)并发布journalctl -u $SERVICE_NAME 的输出?
  • @MarkoLahma 感谢您的评论,请参阅下面的答案。
  • @omajid 感谢您的评论,请参阅下面的答案。

标签: linux .net-core quartz.net systemd


【解决方案1】:

我终于知道是怎么回事。 Program.cs 中 Main 方法的原始结构如下。此代码在 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();
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-07
    相关资源
    最近更新 更多