Skip to content

Move BackgroundService implementation from StartAsync to the new StartedAsync #88605

@steveharter

Description

@steveharter

As part of #87335, there were discussions that BackgroundService implementation should be moved to StartedAsync(). This will allow other IHostedService.StartAsync() implementations to always run before backgroundservice which prevents order-of-registration issues.

Since BackgroundService already has a virtual Start() implementing IHostedService.Start(), we would keep that and explicitly implement the new IHostedLifecycleService members:

API

namespace Microsoft.Extensions.Hosting
{
-   public abstract class BackgroundService : IDisposable, IHostedService

    // Note that IHostedLifecycleService implements IHostedService
+   public abstract class BackgroundService : IDisposable, IHostedLifecycleService

    // Keep this, but this method will no longer implement IHostedService.StartAsync
    public virtual Task StartAsync(CancellationToken cancellationToken);

+   Task IHostedLifecycleService.StartingAsync(CancellationToken cancellationToken); //noop
+   Task IHostedLifecycleService.StartAsync(CancellationToken cancellationToken); //noop
+   Task IHostedLifecycleService.StartedAsync(CancellationToken cancellationToken); //noop
+   Task IHostedLifecycleService.StoppingAsync(CancellationToken cancellationToken); //noop
    // We don't need to explictely implement StopAsync since the existing virtual is fine
+   Task IHostedLifecycleService.StoppedAsync(CancellationToken cancellationToken); //noop
}

Alternative

Note that by implementing the new callbacks, it prevents derived classes from also implementing them. Consider the alternative where the new callbacks are all added as virtuals, but this would be breaking since existing overrides of StartAsync will have pre- and post- behavior broken when calling base.StartAsync() since the base class implementation (BackgroundService) will no longer have any implementation:

namespace Microsoft.Extensions.Hosting
{
-   public abstract class BackgroundService : IDisposable, IHostedService
+   public abstract class BackgroundService : IDisposable, IHostedLifecycleService

+   public virtual Task StartingAsync(CancellationToken cancellationToken); //noop
    public virtual Task StartAsync(CancellationToken cancellationToken); //noop
+   public virtual Task StartedAsync(CancellationToken cancellationToken);
+   public virtual Task StoppingAsync(CancellationToken cancellationToken); //noop
    public virtual Task StopAsync(CancellationToken cancellationToken);
+   public virtual Task StoppedAsync(CancellationToken cancellationToken); //noop
}

Metadata

Metadata

Assignees

Labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions