Arkn.Jobs 0.3.2

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

Arkn.Jobs

Zero-dependency cron scheduler with retry, timeout, distributed lock, persistence, and DLQ — wired into Arkn.Notifications.

Install

dotnet add package Arkn.Jobs

Setup

builder.Services.AddArknJobs(jobs =>
{
    jobs.Add<InvoiceProcessorJob>("0 2 * * *")
        .WithName("invoice-processor")
        .WithDescription("Processes pending invoices at 02:00")
        .WithTimeout(TimeSpan.FromMinutes(10))
        .WithRetry(maxAttempts: 3)
        .NotifyOn(JobEvent.Failed | JobEvent.TimedOut);

    // Optional: in-memory history, DLQ, distributed lock
    jobs.WithInMemoryHistory(capacity: 200)
        .WithInMemoryDlq()
        .WithDistributedLock<MyRedisLock>()
        .OnFailure<SlackNotifier>();  // global fallback notifier
});

Implementing a job

public sealed class InvoiceProcessorJob(IInvoiceService invoices) : IArknJob
{
    public async Task<Result> ExecuteAsync(ArknJobContext ctx)
    {
        ctx.Log("Starting invoice processing batch");

        var result = await invoices.ProcessPendingAsync(ctx.CancellationToken);

        return result.Match(
            onSuccess: count => { ctx.Log($"Processed {count} invoices"); return Result.Success(); },
            onFailure: error => Result.Failure(error));
    }
}

Persistence — IJobHistoryStore

Stores job execution records externally (database, blob, etc.). Default is in-memory:

jobs.WithInMemoryHistory(capacity: 100);   // circular buffer, 100 records per job
jobs.WithHistoryStore<MyEfCoreHistoryStore>(); // custom implementation

Query via IJobHistoryStore.GetRecentAsync(jobName, limit) or the scheduler:

app.MapGet("/jobs/history", (IArknJobScheduler scheduler) =>
    Results.Ok(scheduler.GetAllHistory()));

Distributed Lock — IDistributedJobLock

Prevents concurrent execution across multiple instances. Default (NoOpDistributedJobLock) always acquires — suitable for single-instance deployments:

jobs.WithDistributedLock<RedisDistributedJobLock>(); // plug any IDistributedJobLock impl
public sealed class RedisDistributedJobLock(IConnectionMultiplexer redis) : IDistributedJobLock
{
    public async Task<bool> TryAcquireAsync(string jobName, TimeSpan expiry, CancellationToken ct)
        => await redis.GetDatabase().LockTakeAsync(jobName, Environment.MachineName, expiry);

    public async Task ReleaseAsync(string jobName, CancellationToken ct)
        => await redis.GetDatabase().LockReleaseAsync(jobName, Environment.MachineName);
}

Dead-Letter Queue — IJobDlq

Jobs that exhaust all retry attempts are enqueued in the DLQ. Default is in-memory:

jobs.WithInMemoryDlq();

Inspect and drain the DLQ:

app.MapGet("/jobs/dlq", (InMemoryJobDlq dlq) =>
    dlq.GetEntriesAsync());

app.MapDelete("/jobs/dlq/{jobName}", (string jobName, InMemoryJobDlq dlq) =>
    dlq.ClearAsync(jobName));

Cron expression support

Expression Meaning
* * * * * Every minute
0 2 * * * Daily at 02:00
0 8 * * 1 Every Monday at 08:00
*/5 * * * * Every 5 minutes
0 9,17 * * 1-5 Weekdays at 09:00 and 17:00

Part of the Arkn ecosystem

github.com/fernando-terra/arkn · nuget.org/packages/Arkn.Jobs

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 is compatible.  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
0.3.2 93 5/30/2026
0.3.1 103 5/28/2026
0.3.0 91 5/6/2026
0.2.0 108 5/6/2026
0.1.6 88 5/4/2026
0.1.5 92 5/4/2026
0.1.4 89 5/4/2026
0.1.3 97 5/4/2026
0.1.2 89 5/4/2026
0.1.1 88 5/4/2026
0.1.0 100 5/4/2026