ToolWheel.Extensions.JobManager 1.0.1

dotnet add package ToolWheel.Extensions.JobManager --version 1.0.1
                    
NuGet\Install-Package ToolWheel.Extensions.JobManager -Version 1.0.1
                    
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.1" />
                    
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.1" />
                    
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.1
                    
#r "nuget: ToolWheel.Extensions.JobManager, 1.0.1"
                    
#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.1
                    
#: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.1
                    
Install as a Cake Addin
#tool nuget:?package=ToolWheel.Extensions.JobManager&version=1.0.1
                    
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();
    }
}

Storage Implementations

The core package provides in-memory storage implementations that can be replaced with custom persistence layers via DI.

InMemoryJobStorage

Default implementation of IJobStorage. Maintains an in-memory ConcurrentDictionary of registered jobs.

InMemoryJobTaskStorage

Default implementation of IJobTaskStorage. Tracks all active and completed job tasks in memory.

InMemoryJobTaskJournalStorage

Default implementation of IJobTaskJournalStorage. Stores journal entries for each job task in memory.

InMemoryExtensionOptionStorage

Default implementation of IExtensionOptionStorage. Provides a simple key-value store for extension data.

Custom Storage Example:

// Register a custom storage implementation
builder.Services.AddJobManager(configure =>
{
    configure.ConfigureServices(services =>
    {
        services.AddSingleton<IJobStorage, DatabaseJobStorage>();
        services.AddSingleton<IJobTaskStorage, DatabaseJobTaskStorage>();
        services.AddSingleton<IJobTaskJournalStorage, DatabaseJournalStorage>();
    });
});

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 was computed.  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.1 99 6/12/2026
1.0.1-rc1 93 6/9/2026
1.0.0 105 6/6/2026
1.0.0-rc1 101 6/5/2026