ToolWheel.Extensions.JobManager 1.0.0-preview6

This is a prerelease version of ToolWheel.Extensions.JobManager.
dotnet add package ToolWheel.Extensions.JobManager --version 1.0.0-preview6
                    
NuGet\Install-Package ToolWheel.Extensions.JobManager -Version 1.0.0-preview6
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="ToolWheel.Extensions.JobManager" Version="1.0.0-preview6" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="ToolWheel.Extensions.JobManager" Version="1.0.0-preview6" />
                    
Directory.Packages.props
<PackageReference Include="ToolWheel.Extensions.JobManager" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add ToolWheel.Extensions.JobManager --version 1.0.0-preview6
                    
#r "nuget: ToolWheel.Extensions.JobManager, 1.0.0-preview6"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package ToolWheel.Extensions.JobManager@1.0.0-preview6
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=ToolWheel.Extensions.JobManager&version=1.0.0-preview6&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=ToolWheel.Extensions.JobManager&version=1.0.0-preview6&prerelease
                    
Install as a Cake Tool

ToolWheel.Extensions.JobManager

Core runtime library for the ToolWheel Job Manager. Provides default implementations of the abstractions, the DI registration entry point and the middleware pipeline.

Package Info

Property Value
Target Framework net8.0
NuGet Package ID ToolWheel.Extensions.JobManager
Project Reference ToolWheel.Extensions.JobManager.Abstractions

DI Registration

Callback style

var builder = Host.CreateApplicationBuilder(args);

builder.Services.AddJobManager(configure =>
{
    configure.AddExecutionCondition<MyCondition>();
    configure.AddMiddleware<AuditMiddleware>();
    configure.ConfigureServices(svc => svc.AddSingleton<IAuditLog, FileAuditLog>());

    configure.ConfigureJobs(jobs =>
    {
        var worker = new ReportWorker();
        jobs.Add("daily-report", worker.Generate)
            .Name("Daily Report")
            .Description("Generates the daily sales report")
            .Enabled();
    });
});

Startup class style

builder.Services.AddJobManager<MyStartup>();

public class MyStartup : JobManagerStartup
{
    public override void ConfigureJobManager(IJobManagerConfigurationBuilder configure)
    {
        configure.AddMiddleware<AuditMiddleware>();
    }

    public override void ConfigureJobs(IJobDescriptionCollection collection)
    {
        var worker = new ReportWorker();
        collection.Add("daily-report", worker.Generate)
            .Name("Daily Report")
            .Enabled();
    }
}

Services

JobService

Default implementation of IJobService. Maintains an in-memory ConcurrentDictionary<string, IJob> registry and delegates execution to IJobTaskService.

After a job is registered, Add iterates the features on the IJobDescription and calls IJobManagerFeature.Apply(serviceProvider, jobDescription, job) on each one. This is the single, unified hook for extension features to register per-job data with their runtime services (trigger schedules, retry policies, �). It works identically for jobs registered at startup and for jobs added dynamically at runtime.

var jobService = serviceProvider.GetRequiredService<IJobService>();

// Add � Apply is called for every attached feature
IJob job = jobService.Add(jobDescription);

// Add dynamically at runtime
IJob job = jobService.Add(worker.DoWork, b => b
    .Name("Dynamic Job")
    .WithFeature<TriggerFeature>(f => f.Add(new IntervalTrigger(TimeSpan.FromMinutes(5)))));

IJob? found = jobService.FindById("my-job");
IJob  read  = jobService.ReadById("my-job"); // throws KeyNotFoundException when missing
IEnumerable<IJob> all = jobService.ReadAll();

IJobTask task = await jobService.ExecuteAsync(job);
bool removed  = jobService.Remove(job);

JobTaskService

Default implementation of IJobTaskService. Creates JobTask instances, delegates execution to IJobTaskExecutionService and tracks active tasks.

CancelAllAndWaitAsync signals cancellation on all tracked tasks and awaits their completion � called during graceful shutdown.

JobTaskExecutionService

Builds the middleware pipeline for a job task and executes it. Before the pipeline starts, execution conditions are evaluated via IJobExecutionEvaluatorService. If any condition returns not-ready, the task status is set to NotReady and execution is skipped.

Built-in pipeline steps (innermost last):

  1. JobTaskTargetObjectMiddleware � resolves TargetObject from DI when it is null.
  2. The final step invokes IJob.TargetMethod.

JobExecutionEvaluatorService

Evaluates all registered execution conditions without starting a task and returns the aggregated JobConditionStatus. Useful for pre-flight checks.

var evaluator = serviceProvider.GetRequiredService<IJobExecutionEvaluatorService>();
var status = await evaluator.EvaluateAsync(job);

if (status.Status == JobConditionStatusEnum.NotReady)
    Console.WriteLine($"Job not ready: {status.Message}");

Built-in Middleware and Conditions

Type Purpose
JobTaskTargetObjectMiddleware Resolves the target object from DI. When IJob.UseSingletonInstance is true, the instance is cached and reused across executions.
JobConditionController Default IExecutionConditionController � iterates all conditions and short-circuits on the first not-ready result.
JobEnabledCondition Blocks execution when IJob.Enabled is false.

Singleton Instances

When a job is configured with .AsSingleton(), JobTaskTargetObjectMiddleware creates the target instance once on the first execution and caches it for all subsequent executions. Without .AsSingleton() a fresh instance is resolved from DI on every execution.

jobs.Add<MyWorker>(w => w.Process)
    .Name("Singleton Worker")
    .AsSingleton();

Auto Feature Configuration

AddJobManager scans all loaded assemblies, finds every non-abstract IAutoFeatureConfigurator implementation and calls AutoConfigure(builder) on each. Configurators register services only (middleware, conditions, singletons).

Per-job feature data flows through a separate path:

Startup:  AddJobManager ? IAutoFeatureConfigurator.AutoConfigure   (services)
                        ? JobService.Add ? IJobManagerFeature.Apply (per-job data)

Runtime:  JobService.Add ? IJobManagerFeature.Apply                (per-job data)

Implementing a custom feature

// 1. Feature � override Apply to push per-job data into a runtime service
public class NotifyFeature : IJobManagerFeature
{
    public string WebhookUrl { get; set; } = string.Empty;

    public void Apply(IServiceProvider serviceProvider, IJobDescription jobDescription, IJob job)
    {
        serviceProvider.GetRequiredService<INotifyService>()
            .Register(job.Id, WebhookUrl);
    }
}

// 2. Configurator � registers the runtime service once
public class NotifyConfigurator : IAutoFeatureConfigurator
{
    public void AutoConfigure(IJobManagerConfigurationBuilder builder)
    {
        builder.ConfigureServices(services =>
            services.AddSingleton<INotifyService, NotifyService>());
    }
}

// 3. Usage
jobs.Add("my-job", worker.Run)
    .WithFeature<NotifyFeature>(f => f.WebhookUrl = "https://hooks.example.com/notify");

Job Task Journal

Each IJobTask exposes a Journal of JobTaskJournalEntry records. When a per-job logger is configured via .WithLogger(...), journal entries are forwarded to it through JobTaskJournalLoggerAdapter.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.0-preview6 52 3/26/2026
1.0.0-preview5 53 2/21/2026
1.0.0-preview4 49 2/19/2026