UTimer 2.0.0

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

UTimer

Lightweight, dependency-injection friendly job scheduler for .NET Core applications. Configure processes and run scheduled jobs in the background — one-shot, at a specific time, recurring (fixed period or cron), and continuations.

Install

dotnet add package UTimer

Setup

var builder = Host.CreateApplicationBuilder(args);

builder.Services.AddUTimer(
    maxDegreeOfParallelism: 20,          // queued jobs running concurrently
    maxQueueSize: 1000,                  // bounded queue; enqueue waits when full
    defaultTimeZone: TimeZoneInfo.Local); // cron time zone; null (default) = UTC

var host = builder.Build();
await host.StartAsync();

All jobs are identified by a string job id.

One-shot jobs

// After a delay (runs exactly once)
string id = JobCreator.CreateJob(() => Console.WriteLine("merhaba"), TimeSpan.FromSeconds(5));

// Async — the returned Task is awaited
JobCreator.CreateJob(async () => await File.WriteAllTextAsync("log.txt", "x"));

// Resolve a service from a fresh DI scope
JobCreator.CreateJob<IMailService>(m => m.SendAsync("a@b.c"));

// Control by id
JobCreator.CancelJob(id);              // cancel before it starts (true if cancelled)
await JobCreator.WaitAsync(id);        // wait for completion

At a specific time

JobCreator.CreateJobAt(() => Raporla(), new DateTime(2026, 9, 5, 14, 30, 0)); // local
JobCreator.CreateJobAt<IMailService>(m => m.GonderAsync(), DateTime.UtcNow.AddHours(3));

Past times run immediately. DateTimeKind.Unspecified is treated as local.

Recurring jobs

// Fixed period: first tick immediately, then "period" between the END of one
// run and the START of the next — ticks never overlap.
string id = JobCreator.CreateRecurringJob(() => Temizle(), TimeSpan.FromMinutes(10));

// Cron (uses AddUTimer's defaultTimeZone; pass an explicit TimeZoneInfo to override)
JobCreator.CreateRecurringJob(() => Raporla(), "0 3 * * *");
JobCreator.CreateRecurringJob(() => Raporla(), "30 9 * * 1", TimeZoneInfo.Local);

// Seconds precision (6-field cron)
JobCreator.CreateRecurringJob(() => Tick(), "*/30 * * * * *",
    cronFormat: UTimer.Cronos.CronFormat.IncludeSeconds);

// With a DI service (fresh scope per tick)
var job = JobCreator.CreateRecurringJob<ICacheService>(c => c.Refresh(), TimeSpan.FromHours(1));
JobCreator.CancelJob(job); // stops the repetition

If the expression body returns a Task (e.g. x => x.RefreshAsync()), it is awaited; a slow tick delays the next one instead of overlapping. A throwing iteration is logged and the loop continues.

Continuations

// Enqueue the parent job and capture its Job ID
string parentJobId = JobCreator.CreateJob(() => Console.WriteLine("Parent job running..."));

// Queue a continuation job that runs after the parent job finishes
string childJobId = JobCreator.ContinueWith(
    parentJobId,
    () => Console.WriteLine("Child continuation job running...")
);

Semantics (OnCompletion): the child runs when the parent finishes, whether the parent succeeded or failed. A canceled parent cancels its children. Continuations can be chained (ContinueWith(childJobId, ...)) and work on queued jobs too. Attach them while the parent is pending or within the one-minute completion retention window.

Background queue

var creator = host.Services.GetRequiredService<JobCreator>();
string id = await creator.EnqueueAsync<IOrderService>(s => s.ProcessAsync(order));

Bounded-channel queue drained by a BackgroundService with a concurrency semaphore. CancelJob(id) works until the job starts running.

Shutdown

On host.StopAsync() (or provider disposal): pending jobs are canceled, running jobs are awaited. Jobs that ignore their CancellationToken can delay shutdown indefinitely — use the Func<CancellationToken, Task> overloads for cancellable work.

Limitations

  • In-memory only. A process crash loses pending jobs, continuations and recurring registrations. Re-register recurring jobs at startup; if you need durability, retries and persisted continuations, use Hangfire or Quartz.NET.
  • The static JobCreator facade requires the host to be started (AddUTimer + StartAsync); with multiple hosts in one process the last registered one wins.

License

MIT — see LICENSE. Includes vendored Cronos sources (MIT).

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.

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
2.0.0 38 9/4/2026
1.0.3 173 7/5/2025
1.0.2 151 7/5/2025
1.0.1 168 7/4/2025
1.0.0 263 5/18/2024 1.0.0 is deprecated because it has critical bugs.