Skip to main content 홈 크리에이터 rudironsoni synaxis dotnet-background-services
dotnet-background-services Implements background work. BackgroundService, IHostedService, lifecycle, graceful shutdown.
설치로 이동 Skills Marketplace 커뮤니티가 만든 AI 스킬을 발견하고 탐색하세요.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
직접 명령은 검토 Prompt를 거치지 않습니다. 실행하기 전에 소스를 확인하세요.
npx skills add https://github.com/rudironsoni/Synaxis --skill dotnet-background-services명령은 한 줄로 유지됩니다. 복사하기 전에 가로로 스크롤해 전체 내용을 확인하세요.
로컬 사본을 원하시나요? SkillsMP에서 현재 제공할 수 있는 파일을 다운로드하세요.
Zip 다운로드 다운로드 중... name dotnet-background-services category fundamentals subcategory coding-standards description Implements background work. BackgroundService, IHostedService, lifecycle, graceful shutdown. license MIT targets ["*"] tags ["architecture","dotnet","skill"] version 0.0.1 author dotnet-agent-harness invocable true claudecode {"allowed-tools":["Read","Grep","Glob","Bash","Write","Edit"]} codexcli {"short-description":".NET skill guidance for architecture tasks"} opencode {"allowed-tools":["Read","Grep","Glob","Bash","Write","Edit"]} copilot {} geminicli {} antigravity {}
dotnet-background-services
Patterns for long-running background work in .NET applications. Covers BackgroundService, IHostedService, hosted
service lifecycle, and graceful shutdown handling.
Scope
BackgroundService and IHostedService patterns
Hosted service lifecycle and startup ordering
Graceful shutdown and cancellation handling
Periodic work, polling, and queue-draining loops
Out of scope
DI registration mechanics and service lifetimes -- see [skill:dotnet-csharp-dependency-injection]
Async/await patterns and cancellation token propagation -- see [skill:dotnet-csharp-async-patterns]
Project scaffolding -- see [skill:dotnet-scaffold-project]
Testing strategies for background services -- see [skill:dotnet-testing-strategy] and
[skill:dotnet-integration-testing]
Channel fundamentals and drain patterns -- see [skill:dotnet-channels]
Cross-references: [skill:dotnet-csharp-async-patterns] for async patterns in background workers,
[skill:dotnet-csharp-dependency-injection] for hosted service registration and scope management, [skill:dotnet-channels]
for Channel patterns used in background work queues.
BackgroundService vs IHostedService
Feature BackgroundServiceIHostedServicePurpose Long-running loop or continuous work Startup/shutdown hooks Methods Override ExecuteAsync Implement StartAsync + StopAsync Lifetime Runs until cancellation or host shutdown StartAsync runs at startup, StopAsync at shutdownUse when Polling queues, processing streams, periodic jobs Database migrations, cache warming, resource cleanup
BackgroundService Patterns
Basic Polling Worker
public sealed class OrderProcessorWorker (
IServiceScopeFactory scopeFactory,
ILogger<OrderProcessorWorker> logger ) : BackgroundService
{
{
logger.LogInformation( );
(!stoppingToken.IsCancellationRequested)
{
{
scope = scopeFactory.CreateScope();
processor = scope.ServiceProvider
.GetRequiredService<IOrderProcessor>();
processed = processor.ProcessPendingAsync(stoppingToken);
(processed == )
{
Task.Delay(TimeSpan.FromSeconds( ), stoppingToken);
}
}
(OperationCanceledException) (stoppingToken.IsCancellationRequested)
{
;
}
(Exception ex)
{
logger.LogError(ex, );
Task.Delay(TimeSpan.FromSeconds( ), stoppingToken);
}
}
logger.LogInformation( );
}
}
builder.Services.AddHostedService<OrderProcessorWorker>();
```text
**Always create scopes** -- `BackgroundService` registered a singleton. Inject `IServiceScopeFactory`,
services directly.
**Always handle exceptions** -- , unhandled exceptions `ExecuteAsync`
{
{
logger.LogInformation( );
scope = scopeFactory.CreateScope();
cache = scope.ServiceProvider.GetRequiredService<IProductCache>();
cache.WarmAsync(cancellationToken);
logger.LogInformation( );
}
=> Task.CompletedTask;
}
```text
```
{
IConnection? _connection;
{
logger.LogInformation( );
_connection = CreateConnectionAsync(cancellationToken);
}
{
logger.LogInformation( );
(_connection )
{
_connection.CloseAsync(cancellationToken);
_connection = ;
}
}
{
NotImplementedException();
}
}
```text
---
Understanding the startup shutdown sequence critical correct behavior.
`IHostedService.StartAsync` called each registered service ** registration order**
`BackgroundService.ExecuteAsync` called after `StartAsync` completes (it runs concurrently -- the host does
wait it to finish)
The host ready to serve requests after all `StartAsync` calls complete
**Important:** `ExecuteAsync` must block before yielding to the caller. The first ` ` `ExecuteAsync`
control returns to the host. If you have synchronous setup before the first ` `, keep it move it to
`StartAsync` via an .
```csharp
:
{
{
InitializeAsync(cancellationToken);
.StartAsync(cancellationToken);
}
{
(!stoppingToken.IsCancellationRequested)
{
DoWorkAsync(stoppingToken);
}
}
=> Task.CompletedTask;
=> Task.CompletedTask;
}
```text
`IHostApplicationLifetime.ApplicationStopping` triggered
The host calls `StopAsync` each hosted service ** reverse registration order**
For `BackgroundService`, the stopping token cancelled, then `StopAsync` waits `ExecuteAsync` to complete
`IHostApplicationLifetime.ApplicationStopped` triggered
---
See [skill:dotnet-channels] comprehensive `Channel<T>` guidance including bounded/unbounded options,
`BoundedChannelFullMode`, backpressure strategies, `itemDropped` callbacks, multiple consumers, performance tuning,
drain patterns.
The most common integration a channel-backed background task queue consumed a `BackgroundService`:
```csharp
{
Channel<Func<IServiceProvider, CancellationToken, Task>> _queue
= Channel.CreateBounded<Func<IServiceProvider, CancellationToken, Task>>(
BoundedChannelOptions( ) { FullMode = BoundedChannelFullMode.Wait });
ChannelWriter<Func<IServiceProvider, CancellationToken, Task>> Writer => _queue.Writer;
ChannelReader<Func<IServiceProvider, CancellationToken, Task>> Reader => _queue.Reader;
}
{
{
( queue.Reader.WaitToReadAsync(stoppingToken))
{
(queue.Reader.TryRead( workItem))
{
{
scope = scopeFactory.CreateScope();
workItem(scope.ServiceProvider, stoppingToken);
}
(Exception ex)
{
logger.LogError(ex, );
}
}
}
}
}
builder.Services.AddSingleton<BackgroundTaskQueue>();
builder.Services.AddHostedService<QueueProcessorWorker>();
```text
---
By , the host waits seconds services to stop. Configure -running operations:
```csharp
builder.Services.Configure<HostOptions>(options =>
{
options.ShutdownTimeout = TimeSpan.FromSeconds( );
});
```text
```
{
{
lifetime.ApplicationStarted.Register(() =>
logger.LogInformation( ));
lifetime.ApplicationStopping.Register(() =>
logger.LogInformation( ));
lifetime.ApplicationStopped.Register(() =>
logger.LogInformation( ));
Task.CompletedTask;
}
=> Task.CompletedTask;
}
```text
---
Use `PeriodicTimer` instead of `Task.Delay` more accurate periodic execution:
```
{
{
timer = PeriodicTimer(TimeSpan.FromMinutes( ));
( timer.WaitForNextTickAsync(stoppingToken))
{
{
scope = scopeFactory.CreateScope();
reporter = scope.ServiceProvider
.GetRequiredService<IHealthReporter>();
reporter.ReportAsync(stoppingToken);
}
(Exception ex)
{
logger.LogError(ex, );
}
}
}
}
```text
---
**Do inject services BackgroundService constructors** -- they are singletons. Always use
`IServiceScopeFactory`.
**Do use `Task.Run` background work** -- use `BackgroundService` proper lifecycle management graceful
shutdown.
**Do swallow `OperationCanceledException`** -- it propagate re-check the stopping token. Swallowing it
prevents graceful shutdown.
**Do use `Thread.Sleep`** -- use ` Task.Delay(duration, stoppingToken)` `PeriodicTimer`.
**Do forget to register** -- `AddHostedService<T>()` ; merely implementing the .
---
## ( )
** :** :
1. ** **: ` `
2. ** **: ` `
3. ** **: ` `
4. ** **: ` `
** :**
- ✅ ** **: , , ,
- ✅ ** / **: , ,
- ✅ ** **: ,
** :**
```
# :
: / /
: " "
# :
: " / "
: " / / "
```
##
- [ ]( :
- [ ]( :
- [ ]( :
- [ ]( :
- [ ]( :
protected override async Task ExecuteAsync (CancellationToken stoppingToken )
"Order processor started"
while
try
using
var
var
var
await
if
0
await
5
catch
when
break
catch
"Error processing orders"
await
30
"Order processor stopped"
### Critical Rules for BackgroundService
1.
is
as
not
scoped
2.
by
default
in
stop the host (configurable via
`HostOptions.BackgroundServiceExceptionBehavior` ). Wrap the loop body in try /catch .
3. **Always respect the stopping token** -- check `stoppingToken.IsCancellationRequested` and pass the token to all
async calls.
4. **Back off on empty/error** -- avoid tight polling loops that waste CPU. Use `Task.Delay` with the stopping token.
---
## IHostedService Patterns
### Startup Hook (Cache Warming, Migrations )
```csharp
public sealed class CacheWarmupService (
IServiceScopeFactory scopeFactory,
ILogger<CacheWarmupService> logger ) : IHostedService
public async Task StartAsync (CancellationToken cancellationToken )
"Warming caches"
using
var
var
await
"Cache warmup complete"
public Task StopAsync (CancellationToken cancellationToken )
### Startup + Shutdown (Resource Lifecycle)
csharp
public sealed class MessageBusService (
ILogger<MessageBusService> logger ) : IHostedService
private
public async Task StartAsync (CancellationToken cancellationToken )
"Connecting to message bus"
await
public async Task StopAsync (CancellationToken cancellationToken )
"Disconnecting from message bus"
if
is
not
null
await
null
private static Task<IConnection> CreateConnectionAsync (
CancellationToken ct )
throw
new
## Hosted Service Lifecycle
and
is
for
### Startup Sequence
1.
is
for
in
2.
is
not
for
3.
is
not
await
in
is
where
await
short
or
override
public
sealed
class
MyWorker
BackgroundService
public override async Task StartAsync (CancellationToken cancellationToken )
await
await
base
protected override async Task ExecuteAsync (CancellationToken stoppingToken )
while
await
private Task InitializeAsync (CancellationToken ct )
private Task DoWorkAsync (CancellationToken ct )
### Shutdown Sequence
1.
is
2.
on
in
3.
is
for
4.
is
## Channels Integration
for
and
is
by
public
sealed
class
BackgroundTaskQueue
private
readonly
new
100
public
public
public sealed class QueueProcessorWorker (
BackgroundTaskQueue queue,
IServiceScopeFactory scopeFactory,
ILogger<QueueProcessorWorker> logger ) : BackgroundService
protected override async Task ExecuteAsync (CancellationToken stoppingToken )
while
await
while
out
var
try
using
var
await
catch
"Error executing queued work item"
## Graceful Shutdown
### Host Shutdown Timeout
default
30
for
this
for
long
60
### Responding to Application Lifetime Events
csharp
public sealed class LifecycleLogger (
IHostApplicationLifetime lifetime,
ILogger<LifecycleLogger> logger ) : IHostedService
public Task StartAsync (CancellationToken cancellationToken )
"Application started"
"Application stopping -- begin cleanup"
"Application stopped -- cleanup complete"
return
public Task StopAsync (CancellationToken cancellationToken )
## Periodic Work with PeriodicTimer
for
csharp
public sealed class HealthCheckReporter (
IServiceScopeFactory scopeFactory,
ILogger<HealthCheckReporter> logger ) : BackgroundService
protected override async Task ExecuteAsync (CancellationToken stoppingToken )
using
var
new
1
while
await
try
using
var
var
await
catch
"Health check report failed"
## Agent Gotchas
1.
not
scoped
into
2.
not
for
for
and
3.
not
let
or
4.
not
await
or
5.
not
is
required
interface
does
nothing
Code
Navigation
Serena
MCP
Primary
approach
Use
Serena
symbol
operations
for
efficient
code
navigation
Find
definitions
serena_find_symbol
instead
of
text
search
Understand
structure
serena_get_symbols_overview
for
file
organization
Track
references
serena_find_referencing_symbols
for
impact
analysis
Precise
edits
serena_replace_symbol_body
for
clean
modifications
When
to
use
Serena
vs
traditional
tools
Use
Serena
Navigation
refactoring
dependency
analysis
precise
edits
Use
Read
Grep
Reading
full
files
pattern
matching
simple
text
operations
Fallback
If
Serena
unavailable
traditional
tools
work
fine
Example
workflow
text
Instead
of
Read
src
Services
OrderService.cs
Grep
public
void
ProcessOrder
Use
serena_find_symbol
OrderService
ProcessOrder
serena_get_symbols_overview
src
Services
OrderService.cs
References
Background
tasks
with
hosted
services
https
BackgroundService
https
IHostedService
interface
https
Generic
host
shutdown
https
PeriodicTimer
https