ToolWheel.Extensions.JobManager.Abstractions 1.0.1

dotnet add package ToolWheel.Extensions.JobManager.Abstractions --version 1.0.1
                    
NuGet\Install-Package ToolWheel.Extensions.JobManager.Abstractions -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.Abstractions" 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.Abstractions" Version="1.0.1" />
                    
Directory.Packages.props
<PackageReference Include="ToolWheel.Extensions.JobManager.Abstractions" />
                    
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.Abstractions --version 1.0.1
                    
#r "nuget: ToolWheel.Extensions.JobManager.Abstractions, 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.Abstractions@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.Abstractions&version=1.0.1
                    
Install as a Cake Addin
#tool nuget:?package=ToolWheel.Extensions.JobManager.Abstractions&version=1.0.1
                    
Install as a Cake Tool

ToolWheel.Extensions.JobManager.Abstractions

Public interfaces and contracts for the ToolWheel Job Manager. This package contains no implementations � consumers and extension packages reference these abstractions.

Package Info

Property Value
Target Framework net8.0
NuGet Package ID ToolWheel.Extensions.JobManager.Abstractions
Dependencies Microsoft.Extensions.DependencyInjection.Abstractions, Microsoft.Extensions.Logging.Abstractions

Core Interfaces

IJob

Describes a registered job � an immutable identifier, the MethodInfo to invoke and optional metadata.

public interface IJob
{
    string Id { get; init; }
    MethodInfo TargetMethod { get; init; }
    object? TargetObject { get; init; }
    string Name { get; }
    string Description { get; }
    bool Enabled { get; }
    bool UseSingletonInstance { get; }
    ILogger? JobLogger { get; }
}
Property Description
Id Unique identifier used throughout the system.
TargetMethod The method to invoke when the job executes.
TargetObject The instance to invoke the method on. null means the object is resolved from DI at runtime.
UseSingletonInstance When true, the same target instance is reused across executions instead of creating a new one each time.
JobLogger Optional per-job logger; journal entries are forwarded to it.

IJobTask

Runtime handle for a single execution of a job.

public interface IJobTask
{
    IJob Job { get; }
    string Id { get; }
    JobTaskStatusEnum Status { get; }
    CancellationTokenSource CancellationToken { get; }
    Task? Task { get; }
    object? Result { get; }
    IReadOnlyCollection<JobTaskJournalEntry> Journal { get; }
}

JobTaskStatusEnum values: Pending, Running, Success, Canceled, Failed, NotReady.


IJobService

Central service for registering, querying and executing jobs.

public interface IJobService
{
    IJob Add(IJobDescription jobDescription);
    IJob? FindById(string jobId);
    IJob ReadById(string jobId);
    IEnumerable<IJob> ReadAll();
    bool Remove(IJob job);
    ValueTask<IJobTask> ExecuteAsync(IJob job, CancellationToken cancellationToken = default);
}

After a job is registered, Add calls IJobManagerFeature.Apply on every feature attached to the IJobDescription. This is the unified hook for extension packages to register job-specific configuration (triggers, retry policies, �) both at startup and at runtime.


IJobTaskService

Manages the lifecycle of IJobTask instances at runtime.

public interface IJobTaskService
{
    ValueTask<IJobTask> ExecuteAsync(IJob job, CancellationToken cancellationToken = default);
    void Remove(IJobTask jobTask);
    IEnumerable<IJobTask> ReadAll();
    IEnumerable<IJobTask> ReadByJob(IJob job);
    IEnumerable<IJobTask> ReadByJob(IJob job, params JobTaskStatusEnum[] status);
    Task CancelAllAndWaitAsync(CancellationToken cancellationToken = default);
}

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


IJobExecutionConditionService

Service for storing and retrieving execution condition features per job. Features are keyed by job and feature type so that each job holds at most one instance per feature type.

public interface IJobExecutionConditionService
{
    void Add(IJob job, IJobManagerFeature feature);
    void Add<T>(IJob job, T feature) where T : IJobManagerFeature;
    void Update<T>(IJob job, Action<T> update) where T : IJobManagerFeature;
    T? Get<T>(IJob job) where T : IJobManagerFeature;
    IReadOnlyDictionary<Type, IJobManagerFeature> GetAll(IJob job);
    bool Remove(IJob job, Type featureType);
}

This service is the unified interface for extension packages to store feature-specific data per job. It allows third-party libraries to attach their own feature instances without modifying this service.


IJobTaskJournalService

Service responsible for recording and querying journal entries produced during job task executions.

public interface IJobTaskJournalService
{
    void Append(IJobTask jobTask, JobTaskJournalEntry entry);
    IReadOnlyCollection<JobTaskJournalEntry> GetEntries(IJobTask jobTask);
}

All log entries written during a job execution are routed through this service. When a per-job logger is attached, entries are also forwarded to it.


IJobExecutionStatisticsService

Provides access to aggregated execution statistics for registered jobs.

public interface IJobExecutionStatisticsService
{
    JobExecutionStatistics? GetStatistics(string jobId);
    IEnumerable<JobExecutionStatistics> GetAllStatistics();
    void Record(string jobId, string jobName, TimeSpan duration, JobTaskStatusEnum status);
    void Reset(string jobId);
    void ResetAll();
}

Tracks execution count, success/failure rates, average duration and last execution time for each job.


Configuration API

IJobDescriptionCollection

Typed collection with extension methods for convenient job registration:

// Explicit ID + delegate
collection.Add("my-job", worker.DoWork)
    .Name("My Job")
    .Description("Does the work")
    .Enabled();

// Auto-generated ID
collection.Add(worker.DoWork).Name("My Job");

// Expression � method resolved via reflection, ID auto-generated
collection.Add<MyWorker>(w => w.DoWork).Name("Expression Job");

// Expression with explicit ID
collection.Add<MyWorker>("my-job", w => (Delegate)w.DoWork).Name("Expression Job");

IJobDescriptionBuilder

Fluent builder for configuring a single job description:

collection.Add("job-1", handler.Run)
    .Id("custom-id")          // override the job ID
    .Name("Custom Name")
    .Description("Processes items")
    .Enabled()                // set Enabled = true
    .Disabled()               // set Enabled = false
    .AsSingleton()            // reuse the same target instance
    .WithLogger(myLogger)     // attach a per-job logger
    .WithFeature<MyFeature>(f => f.Setting = true);  // attach an extension feature

IJobManagerConfigurationBuilder

Top-level builder used inside AddJobManager(configure => �):

services.AddJobManager(configure =>
{
    configure
        .ConfigureJobs(jobs => { /* add jobs */ })
        .AddExecutionCondition<MyCondition>()
        .AddExecutionConditionController<MyController>()
        .AddMiddleware<MyMiddleware>()
        .ConfigureServices(svc => svc.AddSingleton<IMyService, MyService>())
        .AddServiceFactory<IMyService>(ServiceLifetime.Singleton, (sp, cfg) => new MyService(cfg));

    configure.SetFeature(new MyFeature());
    var feature = configure.GetFeature<MyFeature>();
});
Methods
Method Description
ConfigureJobs(Action<IJobDescriptionCollection>) Configures job descriptions in the collection.
ConfigureServices(Action<IServiceCollection>) Grants access to the service collection for additional DI registration.
AddServiceFactory<TService>(ServiceLifetime, Func<IServiceProvider, IJobManagerConfiguration, TService>) Registers a factory for a service that receives the current configuration.
AddExecutionCondition<T>() Registers an IExecutionCondition implementation as a singleton.
AddExecutionConditionController<T>() Registers an IExecutionConditionController implementation as a singleton.
AddMiddleware<T>() Registers an IExecutionMiddleware implementation as a singleton.
SetFeature<TFeature>(TFeature) / GetFeature<TFeature>() Attach or retrieve a feature on the configuration builder.

Extensibility Interfaces

IJobManagerFeature

Base interface for feature objects attached to job descriptions or the configuration builder. Override Apply to self-register job-specific data with the appropriate runtime service when IJobService.Add is called.

public interface IJobManagerFeature
{
    // Default no-op � override to register with runtime services.
    void Apply(IServiceProvider serviceProvider, IJobDescription jobDescription, IJob job) { }
}

IAutoFeatureConfigurator

Implementations are auto-discovered at startup by AddJobManager. Each is called once to register services into the DI container (middleware, conditions, singletons). Per-job data is handled separately through IJobManagerFeature.Apply.

public class MyConfigurator : IAutoFeatureConfigurator
{
    public void AutoConfigure(IJobManagerConfigurationBuilder builder)
    {
        builder.ConfigureServices(services =>
            services.AddSingleton<IMyService, MyService>());
        builder.AddMiddleware<MyMiddleware>();
    }
}

Storage Abstractions

The framework defines storage contracts to enable custom persistence implementations beyond the default in-memory stores.

IJobStorage

Central abstraction for job persistence.

public interface IJobStorage
{
    void Add(IJob job);
    IJob? FindById(string jobId);
    bool Remove(string jobId);
    IReadOnlyCollection<IJob> ReadAll();
    bool Contains(string jobId);
}

IJobTaskStorage

Manages persistence of job task instances and their lifecycle data.

public interface IJobTaskStorage
{
    void Add(IJobTask jobTask);
    IJobTask? FindById(string jobTaskId);
    bool Remove(string jobTaskId);
    IReadOnlyCollection<IJobTask> ReadAll();
    IReadOnlyCollection<IJobTask> ReadByJob(string jobId);
}

IJobTaskJournalStorage

Handles persistence of job task journal entries.

public interface IJobTaskJournalStorage
{
    void Append(string jobTaskId, JobTaskJournalEntry entry);
    IReadOnlyCollection<JobTaskJournalEntry> GetEntries(string jobTaskId);
    void Clear(string jobTaskId);
}

IExtensionOptionStorage

Generic storage for feature-specific data, allowing extensions to persist configuration without modifying the core storage interfaces.

public interface IExtensionOptionStorage
{
    void Set(string key, object? value);
    object? Get(string key);
    bool TryGet(string key, out object? value);
    bool Contains(string key);
    bool Remove(string key);
}

IExecutionMiddleware

Pipeline component invoked around each job task execution. Middleware is registered as singleton and runs in the order they are added:

public class LoggingMiddleware : IExecutionMiddleware
{
    public async Task InvokeAsync(IJobTaskContextBuilder context, Func<Task> next, CancellationToken ct)
    {
        Console.WriteLine($"Before: {context.Job.Name}");
        try
        {
            await next();
        }
        finally
        {
            Console.WriteLine($"After: {context.JobTask.Status}");
        }
    }
}

Register via configure.AddMiddleware<LoggingMiddleware>().

Common Use Cases
  • Logging & Auditing: Track job execution start/end and log outcomes.
  • Error Handling: Wrap execution in try-catch and perform recovery logic.
  • Metrics & Statistics: Record execution duration and status.
  • Security & Authorization: Validate permissions before allowing execution.
  • Transaction Management: Open/commit/rollback database transactions.

Execution Conditions

IExecutionCondition

Evaluated before a job runs. Set context.SetNotReady(reason) to block execution:

public class BusinessHoursCondition : IExecutionCondition
{
    public Task EvaluateAsync(ExecutionConditionContext context, CancellationToken ct)
    {
        if (DateTime.Now.Hour < 8 || DateTime.Now.Hour > 18)
            context.SetNotReady("Outside business hours");

        return Task.CompletedTask;
    }
}

Register via configure.AddExecutionCondition<BusinessHoursCondition>().

IExecutionConditionController

Coordinates multiple IExecutionCondition instances and produces a combined JobConditionStatus. The default implementation (JobConditionController) stops on the first not-ready result. Override via configure.AddExecutionConditionController<T>().


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.


Extension Methods

JobDescriptionCollectionExtensions

Convenient fluent methods for adding jobs to an IJobDescriptionCollection:

var collection = new JobDescriptionCollection();

// Add by delegate with explicit ID
collection.Add("job-1", worker.DoWork)
    .Name("My Job")
    .Description("Does the work");

// Add by delegate with auto-generated ID
collection.Add(worker.DoWork)
    .Name("My Job");

// Add by expression (auto-generated ID)
collection.Add<MyWorker>(w => w.DoWork)
    .Name("Expression Job");

// Add by expression with explicit ID
collection.Add<MyWorker>("job-1", w => (Delegate)w.DoWork)
    .Name("Expression Job");

JobServiceExtensions

Runtime methods for adding jobs directly to an IJobService:

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

// Add by delegate
jobService.Add(worker.DoWork, builder =>
{
    builder.Id("job-1")
        .Name("My Job")
        .Enabled();
});

// Add by expression
jobService.Add<MyWorker>(w => w.DoWork, builder =>
{
    builder.Name("Expression Job");
});

Job Lifecycle

  1. Registration: Job is added via IJobService.Add(IJobDescription).

    • IJobManagerFeature.Apply is called on all attached features.
    • Job is stored in IJobStorage.
  2. Querying: Jobs are retrieved via FindById, ReadById, or ReadAll.

  3. Execution: Job is executed via IJobService.ExecuteAsync or IJobTaskService.ExecuteAsync.

    • IExecutionMiddleware pipeline is invoked.
    • IExecutionConditionController evaluates execution readiness.
    • If ready, the target method is invoked within a IJobTask.
    • Journal entries are recorded via IJobTaskJournalService.
    • Execution statistics are recorded via IJobExecutionStatisticsService.
  4. Cancellation & Completion: Task status transitions to Success, Failed, Canceled, or NotReady.


Auto-Configuration

Extension packages can auto-discover and register features without explicit configuration:

// Implement IAutoFeatureConfigurator
public class MyFeatureConfigurator : IAutoFeatureConfigurator
{
    public void AutoConfigure(IJobManagerConfigurationBuilder builder)
    {
        builder.ConfigureServices(services =>
            services.AddSingleton<IMyService, MyService>());
        builder.AddMiddleware<MyMiddleware>();
        builder.AddExecutionCondition<MyCondition>();
    }
}

All implementations of IAutoFeatureConfigurator are discovered and invoked automatically during AddJobManager.


Deprecated Features

?? Note: The AddModuleDescription<T>() method is deprecated. Please configure your services and features directly on the builder instead.

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 (3)

Showing the top 3 NuGet packages that depend on ToolWheel.Extensions.JobManager.Abstractions:

Package Downloads
ToolWheel.Extensions.JobManager.Triggers.Abstractions

Package Description

ToolWheel.Extensions.JobManager

Package Description

ToolWheel.Extensions.JobManager.Conditions

Package Description

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.1 180 6/12/2026
1.0.1-rc1 111 6/9/2026
1.0.0 145 6/6/2026
1.0.0-rc1 124 6/5/2026