如何使用.Net Core编写Linux守护进程

2024-01-04

我可以编写一个长时间运行的 CLI 应用程序并运行它,但我假设它不会满足人们对符合标准的 Linux 守护进程的所有期望(响应 SIGTERM,由 System V init 进程启动,忽略终端 I/O 信号,etc. https://www.python.org/dev/peps/pep-3143/#id1)

大多数生态系统都有一些最佳实践方法来执行此操作,例如,在 python 中,您可以使用https://pypi.python.org/pypi/python-daemon/ https://pypi.python.org/pypi/python-daemon/

有一些关于如何使用 .Net Core 执行此操作的文档吗?


我尝试了一个类似于 .net core Web 主机如何在控制台应用程序中等待关闭的想法。我在 GitHub 上对其进行了审查,并能够提取出他们如何执行此操作的要点Run

https://github.com/aspnet/Hosting/blob/15008b0b7fcb54235a9de3ab844c066aaf42ea44/src/Microsoft.AspNetCore.Hosting/WebHostExtensions.cs#L86 https://github.com/aspnet/Hosting/blob/15008b0b7fcb54235a9de3ab844c066aaf42ea44/src/Microsoft.AspNetCore.Hosting/WebHostExtensions.cs#L86

public static class ConsoleHost {
    /// <summary>
    /// Block the calling thread until shutdown is triggered via Ctrl+C or SIGTERM.
    /// </summary>
    public static void WaitForShutdown() {
        WaitForShutdownAsync().GetAwaiter().GetResult();
    }


    /// <summary>
    /// Runs an application and block the calling thread until host shutdown.
    /// </summary>
    /// <param name="host">The <see cref="IWebHost"/> to run.</param>
    public static void Wait() {
        WaitAsync().GetAwaiter().GetResult();
    }

    /// <summary>
    /// Runs an application and returns a Task that only completes when the token is triggered or shutdown is triggered.
    /// </summary>
    /// <param name="host">The <see cref="IConsoleHost"/> to run.</param>
    /// <param name="token">The token to trigger shutdown.</param>
    public static async Task WaitAsync(CancellationToken token = default(CancellationToken)) {
        //Wait for the token shutdown if it can be cancelled
        if (token.CanBeCanceled) {
            await WaitAsync(token, shutdownMessage: null);
            return;
        }
        //If token cannot be cancelled, attach Ctrl+C and SIGTERN shutdown
        var done = new ManualResetEventSlim(false);
        using (var cts = new CancellationTokenSource()) {
            AttachCtrlcSigtermShutdown(cts, done, shutdownMessage: "Application is shutting down...");
            await WaitAsync(cts.Token, "Application running. Press Ctrl+C to shut down.");
            done.Set();
        }
    }

    /// <summary>
    /// Returns a Task that completes when shutdown is triggered via the given token, Ctrl+C or SIGTERM.
    /// </summary>
    /// <param name="token">The token to trigger shutdown.</param>
    public static async Task WaitForShutdownAsync(CancellationToken token = default (CancellationToken)) {
        var done = new ManualResetEventSlim(false);
        using (var cts = CancellationTokenSource.CreateLinkedTokenSource(token)) {
            AttachCtrlcSigtermShutdown(cts, done, shutdownMessage: string.Empty);
            await WaitForTokenShutdownAsync(cts.Token);
            done.Set();
        }
    }

    private static async Task WaitAsync(CancellationToken token, string shutdownMessage) {
        if (!string.IsNullOrEmpty(shutdownMessage)) {
            Console.WriteLine(shutdownMessage);
        }
        await WaitForTokenShutdownAsync(token);
    }


    private static void AttachCtrlcSigtermShutdown(CancellationTokenSource cts, ManualResetEventSlim resetEvent, string shutdownMessage) {
        Action ShutDown = () => {
            if (!cts.IsCancellationRequested) {
                if (!string.IsNullOrWhiteSpace(shutdownMessage)) {
                    Console.WriteLine(shutdownMessage);
                }
                try {
                    cts.Cancel();
                } catch (ObjectDisposedException) { }
            }
            //Wait on the given reset event
            resetEvent.Wait();
        };

        AppDomain.CurrentDomain.ProcessExit += delegate { ShutDown(); };
        Console.CancelKeyPress += (sender, eventArgs) => {
            ShutDown();
            //Don't terminate the process immediately, wait for the Main thread to exit gracefully.
            eventArgs.Cancel = true;
        };
    }

    private static async Task WaitForTokenShutdownAsync(CancellationToken token) {
        var waitForStop = new TaskCompletionSource<object>();
        token.Register(obj => {
            var tcs = (TaskCompletionSource<object>)obj;
            tcs.TrySetResult(null);
        }, waitForStop);
        await waitForStop.Task;
    }
}

我尝试调整类似的东西IConsoleHost但很快我就意识到我对其进行了过度设计。将主要部分提取为类似的东西await ConsoleUtil.WaitForShutdownAsync();操作就像Console.ReadLine

然后就可以像这样使用该实用程序

public class Program {

    public static async Task Main(string[] args) {
        //relevant code goes here
        //...

        //wait for application shutdown
        await ConsoleUtil.WaitForShutdownAsync();
    }
}

从那里创建一个systemd如以下链接所示,应该可以帮助您完成剩下的工作

用 C# 编写 Linux 守护进程 https://developers.redhat.com/blog/2017/06/07/writing-a-linux-daemon-in-c/

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使用.Net Core编写Linux守护进程 的相关文章

随机推荐

  • Python“if X == Y and Z”语法

    做这个 if key name and item 意思和这个一样 if key name and if key item 如果是这样 我完全困惑了深入 Python 中的示例 5 14 http diveintopython net obj
  • pandas 数据透视表 - 有序类别导致意外的边距

    使用 python 3 7 和 pandas 0 23 4 我正在尝试使用有序分类数据制作数据透视表 如果我包括边距 则小计的顺序似乎不正确 import pandas as pd m male f female data num 0 1
  • 如何在 Xcode 4 中使用 nib 创建自定义 UITableViewCell?

    在 Xcode 3 中 我可以选择在创建表视图单元格子类时创建笔尖 在 Xcode 4 中 它只生成 h m 文件 如何使用 xib 文件创建子类 编辑 参见下面的屏幕截图 EDIT 此外 是否有任何方法可以自动创建 UITableView
  • MySQL 嵌套 JSON 列搜索并提取子 JSON

    我有一个 MySQL 表authors有柱子id name and published books 在这之中 published books是一个 JSON 列 有了样本数据 id name published books 1 Tina 1
  • keydown 事件中的输入验证

    我正在尝试在以下过程中对用户文本输入进行信息验证keydown事件 我试图验证的原因是keydown事件是因为我不想显示那些被认为是非法的字符input开头的盒子 我写的验证是这样的 function validateUserInput v
  • 用于显式实例化一组固定类型的单行代码

    我有一组固定的四种类型A B C and D 以及大量使用这些类型的类和函数模板 为了减少编译时间 我想将这些模板的定义放入 cpp 文件中 并显式实例化这组固定类型的模板 然而 显式实例化引入了很多样板代码 我想减少这些代码 是否有一种优
  • 通过 Scala 中的解析器线程化额外状态

    我先给你讲讲 tl dr 我正在尝试使用状态单子变压器Scalaz 7 https github com scalaz scalaz通过解析器线程化额外的状态 如果不编写一个 我就很难做任何有用的事情lot of t m a gt t m
  • 从自定义 ListAdapter 创建并显示 AlertDialog

    我正在实现一个自定义 ListAdapter 它使用不同的列表项布局来显示某些项目 从该自定义 ListAdapter 中 我实际上想在单击特定按钮时显示 AlertDialog 我实现了 onCreateDialog int 方法 并尝试
  • Android:如何创建启动器

    我以前从未开发过 Android 所以当你回答时请认为我 100 愚蠢 我想创建一个应用程序启动器 它将打开默认的 Web 浏览器到给定的 URL 换句话说 我想用我的网站徽标制作一个图标 当您单击它时 它会在您的默认网络浏览器中打开该网站
  • Html Agility Pack/C#:如何创建/替换标签?

    任务很简单 但我找不到答案 使用 Node Remove 可以轻松删除标签 节点 但是如何替换它们呢 有一个 ReplaceChild 方法 但它需要创建一个新标签 如何设置标签的内容 InnerHtml 和 OuterHtml 是只读属性
  • EF Code First 中自引用外键的语法是什么?

    我正在尝试将外键从 SpouseId 引用到 Contact 表中的 Id 执行此操作的语法是什么 我似乎找不到例子 谢谢 我有一堂这样的课 public class Contact public int Id get set public
  • 在矩阵中查找从左上角到右下角的路径时遇到问题吗?

    我有一个20x30充满随机数的矩阵 0 1 2 我需要找到一条仅由 1 组成的路径 从左上角开始到右下角结束 我需要帮助找到 1 的路径 另外 如何打印我所踏过的每个数字的坐标 我可以显示我所踏过的数字 但在显示其坐标时遇到问题 这是我当前
  • 使用 tostring 聚合字符串并在 r 中对它们进行计数

    应用 dplyr 代码后我得到了以下数据框 Final df lt df gt group by clientID month gt summarise test toString Sector gt as data frame 这给了我以
  • 编辑巨大的sql数据文件

    我有一个 23GB 的文件 我想编辑第 23 行 但服务器上只有 200 MB 可用 RAM 我不想完全打开该文件 因为我只剩下 20GB 可用磁盘空间 我怎样才能做到这一点 我尝试使用 head tail sed 但它似乎创建了一个临时文
  • 具有动态功能的即时应用程序始终显示带有 1 个选项的消歧对话框

    我正在尝试动态功能和即时应用程序 为了在各种功能之间导航 我使用深层链接 每次我导航到另一个 Activity 时 我都会看到消歧对话框 时间不到 1 秒 其中列出了 1 个应用程序 请注意 一次 和 始终 荷兰语 选项是如何变灰的 示例
  • 从 Node 到 Postgres DB 的查询不是 UTF8

    对于一个项目 我确实必须用 JS Node 编写一个服务器 该服务器从 Windows 计算机上的数据库 Postgres 返回元素 一切都 工作正常 连接正常并且返回元素 但是 我确实遇到了编码问题 我的元素是法语的 因此 服务器无法正确
  • 如何在 CasperJS 中禁用 css?

    我知道如何禁用图像和插件 但 CasperJS 中似乎没有禁用 css 的明显选项 有人知道这是如何运作的吗 假设您想禁止加载所有外部样式表 您可以通过中止加载 css 文件的请求来实现 这是通过将函数分配给options onResour
  • Bootstrap 4 导航链接悬停效果

    我试图仅针对导航栏中的 a 链接 而不是正斜杠 放置悬停效果 但我似乎无法只访问 a 链接 效果最终会沿着整个导航栏运行 这里似乎与 Bootstrap 4 有冲突 HTML
  • “区域”之间的 ASP.NET MVC `Html.ActionLink`

    我已向我的 MVC3 项目添加了一个新区域 并且我正在尝试从 Layout 页面链接到新区域 我添加了一个名为 Admin 的区域 其中有一个控制器 Meets 我使用 Visual Studio 设计器添加区域 以便它具有正确的区域注册类
  • 如何使用.Net Core编写Linux守护进程

    我可以编写一个长时间运行的 CLI 应用程序并运行它 但我假设它不会满足人们对符合标准的 Linux 守护进程的所有期望 响应 SIGTERM 由 System V init 进程启动 忽略终端 I O 信号 etc https www p