如何从 Linux 下的 ASP.NET 核心应用程序创建 PID 文件

How to create PID file from ASP.NET Core application under Linux

我写了一个 ASP.NET 核心应用程序(实际上是 .NET 5),运行 它在 Linux 下作为系统服务(在 this Microsoft guide). Then I wanted to monitor this application with monit 应用程序之后。这个应用程序需要服务来创建 PID 文件,以便它们很容易被发现。我决定写一个问答式的问题来帮助其他人更快地实现同样的目标。

注意:此处描述的解决方案是我 NuGet package with open source available on github 的一部分,以防您更喜欢通过打包方式实现目标。

IHostedService

.NET Core 中有几种方法可以 运行 后台任务。 IHostedService 是其中一个包含 StartAsync 方法的方法,该方法在注册服务后在启动时调用。该接口还定义了在正常关闭时调用的 StopAsync 。有关 IHostedService.

的更多详细信息,请访问 this Microsoft page

知道我们可以创建自己的 IHostedService 来管理我们应用程序的 PID 文件:

public class PidFileHostedService : IHostedService
{
    private readonly ILogger<PidFileHostedService> logger;
    private readonly IConfiguration configuration;
    private readonly IWebHostEnvironment env;

    private bool isPidFileCreated = false;
    private string pidFile = string.Empty;

    public PidFileHostedService(ILogger<PidFileHostedService> logger,
        IConfiguration configuration,
        IWebHostEnvironment env)
    {
        this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
        this.configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
        this.env = env ?? throw new ArgumentNullException(nameof(env));
    }

    public async Task StartAsync(CancellationToken cancellationToken)
    {
        try
        {
            if (env.IsDevelopment())
                return;

            pidFile = configuration.GetValue<string>("PidFile");

            if (string.IsNullOrWhiteSpace(pidFile))
                return;

            await WritePidFile();
            
            isPidFileCreated = true;
        }
        catch (Exception ex)
        {
            logger.LogError(ex, $"Unexpected error when starting {nameof(PidFileHostedService)}", null);
        }
    }

    private async Task WritePidFile()
    {
        var processId = Environment.ProcessId.ToString();
        await File.WriteAllTextAsync(pidFile, processId);
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        try
        {
            if (isPidFileCreated)
                File.Delete(pidFile);
        }
        catch (Exception ex)
        {
            logger.LogError(ex, "Unexpected error when deleting PID file", null);
        }
        
        return Task.CompletedTask;
    }
}

此服务假定应用程序的 appsettings.json 文件中存在 PidFile 属性。 不要忘记在 Startup.cs:

中注册服务
services.AddHostedService<PidFileHostedService>();

服务文件更改

正如我在问题中所写,我使用了 Microsoft guide on how to make my app run as a systemd service。现在,在更改之后,该服务必须对将在其中创建 PID 文件的目录具有必要的权限。可以将具有必要权限的此目录的创建委托给 systemd。将此行添加到 [Service] 部分下的服务文件中就足够了:

RuntimeDirectory=helloapp

感谢这一行,systemd 将在每个服务启动时在 /var/run 中创建 helloapp 子目录,并具有必要的权限。将以下行添加到同一部分也是一个好主意,这将告诉 systemd 在应用程序停止后仔细检查 PID 文件是否被删除:

PIDFile=/var/run/helloapp/helloapp.pid