Skip to content

AddSystemd should only check for NOTIFY_SOCKET env #88660

@crozone

Description

@crozone

Microsoft.Extensions.Hosting.SystemdHostBuilderExtensions.AddSystemd() calls SystemdHelpers.IsSystemdService() to determine whether it should add the SystemdNotifier and SystemdLifetime services to the services container.

IsSystemdService() goes out of its way to try and verify that its parent process is actually called "systemd", and also has an additional edgecase for PID 1 for if it is invoked in a service container.

Reference: https://github.com/dotnet/runtime/blob/076f8c58984b009033204ad1dd9f86c691ae42fb/src/libraries/Microsoft.Extensions.Hosting.Systemd/src/SystemdHostBuilderExtensions.cs#L68-L77`

I can't see any reason why the check needs to be this strict and specific. It also appears to have a few drawbacks:

  • This check only works with services directly invoked from systemd, but this isn't actually required. AddSystemd() is primarily concerned with notifying the NOTIFY_SOCKET (aka sd_notify) that the service has started up or is shutting down. Non-systemd systems often include tools like start-stop-daemon which also support a minimal NOTIFY_SOCKET interface, but are needlessly excluded by this check.

  • This check causes false positives when the service is invoked from systemd on an interactive shell, for example: UseSystemd can detect an interactive shell as running as systemd service extensions#2525. AFAIK this issue is marked as resolved but has not actually been fixed.

  • This check causes a false positive if the service is not configured as Type=notify.

  • The code is more complicated and requires a workaround for container invocation where the PID is 1 and there is no parent systemd process.

A significantly simpler and more robust solution would be to only check for the presence of the NOTIFY_SOCKET environment variable (and also that we're on Unix). If NOTIFY_SOCKET is set, it should be notified, otherwise don't notify it. The presence of the environment variable should be enough of an indication that the interface is supported and notification is required.

The current SystemdHelpers.IsSystemdService() could still be used for changing the log format.

Example of AddSystemd() with changes:

public static IServiceCollection AddSystemd(this IServiceCollection services)
{
    ThrowHelper.ThrowIfNull(services);

    if (SystemdHelpers.IsSystemdService())
    {
        services.Configure<ConsoleLoggerOptions>(options =>
        {
            options.FormatterName = ConsoleFormatterNames.Systemd;
        });
    }

    if (Environment.OSVersion.Platform == PlatformID.Unix &&
        !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("NOTIFY_SOCKET")))
    {
        services.AddSingleton<ISystemdNotifier, SystemdNotifier>();
        services.AddSingleton<IHostLifetime, SystemdLifetime>();
    }

    return services;
}

Does this seem like a sensible change to consider?

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions