-
-
Save marafiq/c3e08c1892600cda1a0af8df00358a2e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Licensed to the .NET Foundation under one or more agreements. | |
// The .NET Foundation licenses this file to you under the MIT license. | |
using System; | |
using System.Threading; | |
using System.Threading.Tasks; | |
namespace Microsoft.Extensions.Hosting | |
{ | |
/// <summary> | |
/// Base class for implementing a long running <see cref="IHostedService"/>. | |
/// </summary> | |
public abstract class BackgroundService : IHostedService, IDisposable | |
{ | |
private Task _executeTask; | |
private CancellationTokenSource _stoppingCts; | |
/// <summary> | |
/// Gets the Task that executes the background operation. | |
/// </summary> | |
/// <remarks> | |
/// Will return <see langword="null"/> if the background operation hasn't started. | |
/// </remarks> | |
public virtual Task ExecuteTask => _executeTask; | |
/// <summary> | |
/// This method is called when the <see cref="IHostedService"/> starts. The implementation should return a task that represents | |
/// the lifetime of the long running operation(s) being performed. | |
/// </summary> | |
/// <param name="stoppingToken">Triggered when <see cref="IHostedService.StopAsync(CancellationToken)"/> is called.</param> | |
/// <returns>A <see cref="Task"/> that represents the long running operations.</returns> | |
protected abstract Task ExecuteAsync(CancellationToken stoppingToken); | |
/// <summary> | |
/// Triggered when the application host is ready to start the service. | |
/// </summary> | |
/// <param name="cancellationToken">Indicates that the start process has been aborted.</param> | |
public virtual Task StartAsync(CancellationToken cancellationToken) | |
{ | |
// Create linked token to allow cancelling executing task from provided token | |
_stoppingCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); | |
// Store the task we're executing | |
_executeTask = ExecuteAsync(_stoppingCts.Token); | |
// If the task is completed then return it, this will bubble cancellation and failure to the caller | |
if (_executeTask.IsCompleted) | |
{ | |
return _executeTask; | |
} | |
// Otherwise it's running | |
return Task.CompletedTask; | |
} | |
/// <summary> | |
/// Triggered when the application host is performing a graceful shutdown. | |
/// </summary> | |
/// <param name="cancellationToken">Indicates that the shutdown process should no longer be graceful.</param> | |
public virtual async Task StopAsync(CancellationToken cancellationToken) | |
{ | |
// Stop called without start | |
if (_executeTask == null) | |
{ | |
return; | |
} | |
try | |
{ | |
// Signal cancellation to the executing method | |
_stoppingCts.Cancel(); | |
} | |
finally | |
{ | |
// Wait until the task completes or the stop token triggers | |
await Task.WhenAny(_executeTask, Task.Delay(Timeout.Infinite, cancellationToken)).ConfigureAwait(false); | |
} | |
} | |
public virtual void Dispose() | |
{ | |
_stoppingCts?.Cancel(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment