DKNet

Run a concurrent startup batch

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;
}

Task.WhenAll invokes per-task wrappers that catch RunAsync exceptions and let the other tasks finish.

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.

⚙️ Configuration reference

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.

⚠️ Gotchas & limits