Skip to content
Development
Skill

/worker-services

Build long-running .NET background services with `BackgroundService`, Generic Host, graceful shutdown, configuration, logging, and deployment patterns suited to workers and daemons. USE FOR: background services; scheduled workers; hosted services; worker extraction; graceful

From plugin
dotnet-skills
466200 skills50 agents
Install
$ npx -y skills add managedcode/dotnet-skills --skill worker-services --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/worker-services

Context preview

The summary Claude sees to decide when to auto-load this skill.

Build long-running .NET background services with `BackgroundService`, Generic Host, graceful shutdown, configuration, logging, and deployment patterns suited to workers and daemons. USE FOR: background services; scheduled workers; hosted services; worker extraction; graceful

SKILL.md

worker-services.SKILL.md
name: worker-services
description: "Build long-running .NET background services with `BackgroundService`, Generic Host, graceful shutdown, configuration, logging, and deployment patterns suited to workers and daemons. USE FOR: background services; scheduled workers; hosted services; worker extraction; graceful shutdown, health checks, and service hosting review. DO NOT USE FOR: unrelated stacks; generic tasks that do not need this specific guidance. INVOKES: inspect the repository context, edit targeted files, and run relevant build, test, lint, or validation commands when changes are made."
compatibility: "Requires a worker, hosted service, or background-processing scenario."

.NET Worker Services

Trigger On

  • building long-running background services or scheduled workers
  • adding hosted services to an app or extracting them into a worker process
  • reviewing graceful shutdown, cancellation, queue processing, or health behavior

Documentation

  • [Worker Services in .NET](https://learn.microsoft.com/en-us/dotnet/core/extensions/workers)
  • [Background tasks with hosted services in ASP.NET Core](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/host/hosted-services?view=aspnetcore-10.0)
  • [Create Windows Service using BackgroundService](https://learn.microsoft.com/en-us/dotnet/core/extensions/windows-service)
  • [App health checks in .NET](https://learn.microsoft.com/en-us/dotnet/core/diagnostics/diagnostic-health-checks)
  • [Health checks in ASP.NET Core](https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/health-checks?view=aspnetcore-10.0)

References

  • [patterns.md](references/patterns.md) - BackgroundService patterns, graceful shutdown, and health check implementations
  • [anti-patterns.md](references/anti-patterns.md) - Common worker service mistakes and how to avoid them

Workflow

1. **Use BackgroundService as your base class:**

  • Provides standard `StartAsync`/`StopAsync` handling
  • Focus on implementing `ExecuteAsync` only
  • Proper cancellation token management built-in

2. **Handle scoped dependencies correctly:**

  • Create service scopes for scoped services
  • No scope is created by default in hosted services

3. **Implement graceful shutdown:**

  • Propagate cancellation tokens throughout
  • Complete work promptly when token fires
  • Avoid ungraceful shutdown at timeout

4. **Keep execution loop thin:**

  • Move business logic to testable services
  • Handle exceptions to prevent service crashes
  • Use `PeriodicTimer` for scheduled work

5. **Add observability:**

  • Use health checks for readiness/liveness
  • Expose metrics and structured logging
  • Consider distributed locks for multi-instance

Current Upstream Notes

  • `.NET runtime` `v10.0.10` is servicing. For workers, rerun cancellation, graceful shutdown, long-running GC/pinning, EventPipe diagnostics, NativeAOT, and platform-specific filesystem/drive checks after upgrading rather than changing architecture by default.
  • Use the refreshed Worker Services and hosted-service Learn pages for exact current hosting and health-check APIs when adding new worker entry points.

Basic BackgroundService Pattern

Simple Worker

public class Worker : BackgroundService
{
    private readonly ILogger<Worker> _logger;

    public Worker(ILogger<Worker> logger)
    {
        _logger = logger;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        _logger.LogInformation("Worker starting");

        while (!stoppingToken.IsCancellationRequested)
        {
            try
            {
                _logger.LogInformation("Worker running at: {Time}", DateTimeOffset.Now);
                await DoWorkAsync(stoppingToken);
                await Task.Delay(TimeSpan.FromSeconds(5), stoppingToken);
            }
            catch (OperationCanceledException) when (stoppingToken.IsCancellationRequested)
            {
                // Graceful shutdown, not an error
                break;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error in worker iteration");
                // Continue or break based on error severity
            }
        }

        _logger.LogInformation("Worker stopping");
    }

    private async Task DoWorkAsync(CancellationToken cancellationToken)
    {
        // Business logic here
    }
}

Using PeriodicTimer (Recommended)

public class TimedWorker : BackgroundService
{
    private readonly ILogger<TimedWorker> _logger;
    private readonly IServiceScopeFactory _scopeFactory;
    private readonly TimeSpan _period = TimeSpan.FromMinutes(1);

    public TimedWorker(ILogger<TimedWorker> logger, IServiceScopeFactory scopeFactory)
    {
        _logger = logger;
        _scopeFactory = scopeFactory;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        using var timer = new PeriodicTimer(_period);

        while (await timer.WaitForNextTickAsync(stoppingToken))
        {
            try
            {
                await using var scope = _scopeFactory.CreateAsyncScope();
                var processor = scope.ServiceProvider.GetRequiredService<IDataProcessor>();
                await processor.ProcessAsync(stoppingToken);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error processing scheduled task");
            }
        }
    }
}

Handling Scoped Dependencies

Correct Pattern with Scope Factory

public class ScopedWorker : BackgroundService
{
    private readonly IServiceScopeFactory _scopeFactory;
    private readonly ILogger<ScopedWorker> _logger;

    public ScopedWorker(IServiceScopeFactory scopeFactory, ILogger<ScopedWorker> logger)
    {
        _scopeFactory = scopeFactory;
        _logger = logger;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
Read more
Ships withdotnet-skills

Stop explaining .NET to your AI. Start building. We've all been there: asking Claude to use Entity Framework, only to get EF6 patterns in a .NET 8 project. Explaining to Copilot that Blazor Server and Blazor WebAssembly aren't the same thing.

Get the whole plugin

Other skills on dotnet-skills.