Arkn.Jobs
0.3.2
dotnet add package Arkn.Jobs --version 0.3.2
NuGet\Install-Package Arkn.Jobs -Version 0.3.2
<PackageReference Include="Arkn.Jobs" Version="0.3.2" />
<PackageVersion Include="Arkn.Jobs" Version="0.3.2" />
<PackageReference Include="Arkn.Jobs" />
paket add Arkn.Jobs --version 0.3.2
#r "nuget: Arkn.Jobs, 0.3.2"
#:package Arkn.Jobs@0.3.2
#addin nuget:?package=Arkn.Jobs&version=0.3.2
#tool nuget:?package=Arkn.Jobs&version=0.3.2
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 | Versions 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. |
-
net10.0
- Arkn.Core (>= 0.3.2)
- Arkn.Logging (>= 0.3.2)
- Arkn.Notifications (>= 0.3.2)
- Arkn.Results (>= 0.3.2)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.7)
- Microsoft.Extensions.Hosting.Abstractions (>= 10.0.7)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.7)
-
net8.0
- Arkn.Core (>= 0.3.2)
- Arkn.Logging (>= 0.3.2)
- Arkn.Notifications (>= 0.3.2)
- Arkn.Results (>= 0.3.2)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.7)
- Microsoft.Extensions.Hosting.Abstractions (>= 10.0.7)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.7)
-
net9.0
- Arkn.Core (>= 0.3.2)
- Arkn.Logging (>= 0.3.2)
- Arkn.Notifications (>= 0.3.2)
- Arkn.Results (>= 0.3.2)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.7)
- Microsoft.Extensions.Hosting.Abstractions (>= 10.0.7)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.7)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.