WJb 0.104.0

dotnet add package WJb --version 0.104.0
                    
NuGet\Install-Package WJb -Version 0.104.0
                    
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="WJb" Version="0.104.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="WJb" Version="0.104.0" />
                    
Directory.Packages.props
<PackageReference Include="WJb" />
                    
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 WJb --version 0.104.0
                    
#r "nuget: WJb, 0.104.0"
                    
#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 WJb@0.104.0
                    
#: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=WJb&version=0.104.0
                    
Install as a Cake Addin
#tool nuget:?package=WJb&version=0.104.0
                    
Install as a Cake Tool

⚡ WJb — Explicit Job Execution Engine

If you can’t explain why a job runs — you don’t control your system.


💥 The Problem

Most job systems eventually become:

Job → retry → pipeline → middleware → ???

Questions become difficult to answer:

  • Why did this job run?
  • Who scheduled the next step?
  • Why was it retried?
  • What actually happens under the hood?

✅ The WJb Way

Job → Executor → Action → ActionResult → Next Jobs

✔ Explicit execution

✔ Explicit workflow

✔ Explicit retries

✔ No hidden pipelines

✔ No magic


🧠 Core Concepts

Action

Your business logic.

public sealed class SendEmailAction
    : JobAction<SendEmailInput>
{
    public const string Key = "send-email";

    public override Task<ActionResult> ExecuteAsync(
        SendEmailInput input,
        CancellationToken ct)
    {
        Console.WriteLine($"Sending email to {input.To}");

        return Task.FromResult(ActionResults.None());
    }
}

ActionResult

Defines what happens next.

return ActionResults.None();

or

return ActionResults.Next(
    new JobCommand(
        LogAction.Key,
        new LogInput
        {
            Message = "Email sent"
        }));

JobCommand

Explicitly schedules the next job.

new JobCommand(
    LogAction.Key,
    new LogInput
    {
        Message = "Done"
    })

No hidden orchestration.

The action decides the workflow.


🚀 Minimal Start

public sealed class LogAction : JobAction<LogInput>
{
    public const string Key = "log";

    public override Task<ActionResult> ExecuteAsync(
        LogInput input,
        CancellationToken ct)
    {
        Console.WriteLine(input.Message);

        return Task.FromResult(ActionResults.None());
    }
}

var wjb = WJbBuilder.Create(cfg =>
{
    cfg.AddAction<LogAction>(LogAction.Key);
});

var action = await wjb.CreateAsync<LogAction>();

await action.ExecuteAsync(
    new LogInput
    {
        Message = "Hello WJb 👋"
    });

📦 Configuring Services

Actions can receive dependencies through constructor injection.

var wjb = WJbBuilder.Create(cfg =>
{
    cfg.AddSetting(new SmtpSettings
    {
        Host = "localhost"
    });

    cfg.AddAction<SendEmailAction>(
        SendEmailAction.Key);
});

Action:

public sealed class SendEmailAction(
    SmtpSettings settings)
    : JobAction<SendEmailInput>
{
    public const string Key = "send-email";

    public override Task<ActionResult> ExecuteAsync(
        SendEmailInput input,
        CancellationToken ct)
    {
        Console.WriteLine(settings.Host);

        return Task.FromResult(ActionResults.None());
    }
}

⚙️ Background Job Execution

Configure WJb:

var store = new InMemoryStore();

var wjb = WJbBuilder.Create(cfg =>
{
    cfg.AddAction<SendEmailAction>(
        SendEmailAction.Key);

    cfg.AddSetting(new SmtpSettings
    {
        Host = "smtp.local"
    });

    cfg.UseStore(store);
});

Queue a job:

await wjb.Executor!.EnqueueAsync(
    SendEmailAction.Key,
    new
    {
        to = "test@test.com"
    });

Run a single execution cycle:

await wjb.Executor.ExecuteOnceAsync();

Or run continuously:

await wjb.Executor.ExecuteLoopAsync();

🔗 Workflows

Actions explicitly define the next step.

public sealed class AAction
    : JobAction<EmptyInput>
{
    public const string Key = "a";

    public override Task<ActionResult> ExecuteAsync(
        EmptyInput input,
        CancellationToken ct)
    {
        return Task.FromResult(
            ActionResults.Next(
                new JobCommand(
                    BAction.Key,
                    new EmptyInput())));
    }
}

public sealed class BAction
    : JobAction<EmptyInput>
{
    public const string Key = "b";

    public override Task<ActionResult> ExecuteAsync(
        EmptyInput input,
        CancellationToken ct)
    {
        return Task.FromResult(ActionResults.None());
    }
}
A → B → C

No workflow engine required.


🔄 Retries

Retries are configured per job.

await wjb.Executor.EnqueueAsync(
    ImportAction.Key,
    new ImportInput(),
    new JobOptions
    {
        MaxRetries = 3,
        RetryDelay = TimeSpan.FromSeconds(10)
    });

🆚 Why WJb?

Feature WJb
Explicit workflows
Explicit retries
Constructor injection
Typed actions
Background execution
Hidden pipelines
Hidden orchestration
Magic execution

✅ Use WJb If

You want:

  • predictable execution
  • explicit workflows
  • strongly-typed actions
  • business-driven process orchestration
  • simple, testable background jobs

❌ WJb Is Not For You If

You want:

  • convention-based magic
  • invisible pipelines
  • workflow definitions hidden in configuration
  • execution that is difficult to trace

⚡ TL;DR

Action = Business Logic
ActionResult = Outcome
JobCommand = Next Step
Executor = Runner

You always know:

  • why a job started
  • what it did
  • what it scheduled next

🎁 Support WJb

If WJb changed how you think about background jobs:

👉 https://ko-fi.com/ukrguru


🎉 Early Support Bonus

Any donation before August 1, 2026 qualifies for:

👉 FREE Solo License


WJb exists because background jobs shouldn't be magic.

Product Compatible and additional computed target framework versions.
.NET 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.
  • net10.0

    • No dependencies.

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
0.104.0 43 7/7/2026
Loading failed

Initial public release of WJb.

           Features:
           - Explicit job execution model
           - Typed actions and payload binding
           - Action chaining via ActionResult and JobCommand
           - In-memory job storage
           - Job retries and cancellation support
           - Constructor-based dependency injection
           - Workflow execution engine
           - Service registry and action factory
           - Lightweight, testable architecture