如何使用 .Net Core 编写 linux 守护进程 [英] How to write a linux daemon with .Net Core

查看:46
本文介绍了如何使用 .Net Core 编写 linux 守护进程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I could just write a long-running CLI app and run it, but I'm assuming it wouldn't comply to all the expectations one would have of a standards-compliant linux daemon (responding to SIGTERM, Started by System V init process, Ignore terminal I/O signals, etc.)

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

Most ecosystems have some best-practice way of doing this, for example, in python, you can use https://pypi.python.org/pypi/python-daemon/

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

Is there some documentation about how to do this with .Net Core?

推荐答案

我想到了一个类似于 .net 核心 Web 主机如何在控制台应用程序中等待关闭的想法.我正在 GitHub 上查看它,并且能够提取出他们如何执行 Run

I toyed with an idea similar to how .net core web host waits for shutdown in console applications. I was reviewing it on GitHub and was able to extract the gist of how they performed the Run

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

I tried adapting something like a IConsoleHost but quickly realized I was over-engineering it. Extracted the main parts into something like await ConsoleUtil.WaitForShutdownAsync(); that operated like Console.ReadLine

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

This then allowed the utility to be used like this

public class Program {

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

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

从那里创建一个systemd,如下面的链接应该让你完成剩下的工作

from there creating a systemd as in the following link should get you the rest of the way

编写 Linux 守护进程C#

这篇关于如何使用 .Net Core 编写 linux 守护进程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆