Switchknife.Journal 0.2.0

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

Switchknife.Journal

A durable step journal on SQLite for processes that must survive a restart in the middle of their work.

A step is one side effect with a stable key inside a flow (batch-7, prep/task-3). RunAsync records the step's intent before it runs and its result after:

  • a completed key never runs again; its recorded result comes back;
  • a key whose earlier attempt recorded its intent and never its outcome (a crash, a kill, a cancellation) runs again with context.Resumed = true, so the step adopts or removes what that attempt left;
  • a step that throws is recorded as failed and rethrown; the next run of the key is a fresh attempt.
await using var journal = await StepJournal.OpenAsync("state/journal.db");

var container = await journal.RunAsync("batch-7", "prep/task-3", async (step, ct) =>
{
    var name = $"prep-{step.Flow}-task-3";          // deterministic: a resumed attempt finds what it made
    if (step.Resumed)
        await engine.RemoveIfExistsAsync(name, ct);   // adopt or remove what the interrupted attempt left
    return await engine.CreateAndStartAsync(name, ct);
}, MyJson.Default.ContainerInfo);

await journal.AppendEventAsync("batch-7", "task_started", """{"task":"task-3"}""");
var replay = await journal.ReadEventsAsync("batch-7", after: lastSeen);
var leftovers = await journal.UnfinishedAsync();     // on start: what a crash left mid-step

To run a side effect again under the same key on purpose (a workspace volume removed and prepared again under the same run id), reset the step first; the next run is a first attempt:

await journal.ResetAsync("batch-7", "prep/task-3");   // true when there was a record; throws when the step is still started

Guarantees and limits:

  • A step runs at least once; its result is recorded at most once. A step that finished but crashed before its result was written runs again, resumed, so make each step safe to repeat for its key.
  • ResetAsync removes a completed or failed step's record, so its key runs as a first attempt (Attempt 1, Resumed false); it returns false when the key had no record. Reset is your statement that the earlier effect is gone or may repeat: the journal cannot check it. A started step is refused (InvalidOperationException): an interrupted attempt must be resumed, not forgotten.
  • Every commit is synced to disk (synchronous = FULL, WAL).
  • One process owns a journal file; calls are serialized inside it. Run one step of a given key at a time.
  • Results are stored as JSON through a JsonTypeInfo<T> you pass (source-generated), so it works with Native AOT.
  • Not a workflow engine: no timers, no scheduling, no distribution. It records what happened so your own code can decide what to do next.
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
0.2.0 289 10/13/2026
0.1.0 149 10/13/2026