Part of DKNet.AspCore.Tasks. BackgroundJobHost opens one async scope, resolves all tasks, and awaits Task.WhenAll. A task can open a private scope when its dependencies must not be shared with other concurrent tasks:
using DKNet.AspCore.Tasks;
using Microsoft.Extensions.DependencyInjection;
var services = new ServiceCollection();
services.AddScoped<Work>();
await using var provider = services.BuildServiceProvider();
await new IsolatedTask(provider.GetRequiredService<IServiceScopeFactory>()).RunAsync();
public sealed class IsolatedTask(IServiceScopeFactory scopes) : IBackgroundTask
{
public async Task RunAsync(CancellationToken cancellationToken = default)
{
await using var scope = scopes.CreateAsyncScope();
await scope.ServiceProvider.GetRequiredService<Work>().RunAsync(cancellationToken);
}
}
public sealed class Work
{
public Task RunAsync(CancellationToken token) => Task.CompletedTask;
}
Each RunAsync exception is caught and logged with the exception attached. Its message is plain text: the task’s full type name followed by ` job failed`, assembled through string interpolation before logging, rather than a structured placeholder. Other tasks continue. The scope is disposed after the batch. Dependency construction and enumeration happen outside that per-task catch.
| Input | Type | Default | Effect |
|---|---|---|---|
cancellationToken |
CancellationToken |
default in interface | Host passes its stopping token; tasks must observe it. |
There are no ordering, retry, concurrency-limit, or per-task-timeout settings.
DbContext; open private scopes for non-thread-safe dependencies.RunAsync, are caught. There is no retry, rollback or compensation.RunAsync error wrapper.