All notable changes to the Restate .NET SDK will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
BuildAwakeableIdrewritten withSystem.Buffers.Text.Base64Url— eliminates 3-4 intermediate string allocations per awakeable- Serialization hot path (
Run,SetState,Call) usesArrayPool<byte>rentals viaCopyToPooledinstead of.ToArray()— reduces GC pressure for typical 50-500 byte payloads - Replay journal entries use
RawMessage.DetachPayload()ownership transfer — eliminates 1byte[]copy per replayed entry CompletionManagerusesCompletionSlotdiscriminated union struct instead ofConcurrentDictionary<int, object>— eliminates boxing ofCompletionResulton early completionsProtocolReadersingle-segment fast paths for header parsing and payload copy — avoidsstackalloc+ReadOnlySequence.CopyTooverhead on the common Kestrel pathNegotiateVersionuses explicit version substring checks instead of loop iteration
- NativeAotCounter sample port 9088 → 9086 to match CI integration test expectations
- NativeAotSaga sample port 9089 → 9087 to match CI integration test expectations
- Retry policy support for
ctx.Run()side effects with configurable exponential backoff (RetryPolicy) - Idempotency key support via
CallOptionsfor service-to-service calls CancelInvocation(string invocationId)API for cancelling running invocations- Native AOT support:
BuildAot(),AddRestateAot(),RegistrationEmittersource generator - 5 new samples: FanOut, Saga, NativeAotGreeter, NativeAotCounter, NativeAotSaga
- Mock context support for RetryPolicy, CallOptions, and CancelInvocation in
Restate.Sdk.Testing - Interface conformance tests for new API surface
ProtocolReaderdouble-complete on dispose — idempotent guard prevents crash (contributed by @stevefan1999-personal)ProtocolWriterdouble-complete on dispose — same idempotent guard pattern- Journal index misalignment after retry exhaustion when handler continues (saga compensation pattern)
- Sample port conflicts — all 9 samples now have unique ports (9080–9089)
- Solution file updated to include all new sample projects
- Lambda handler API: use generic
Bind<T>()instead ofAction<Type>for type-safe handler registration
- NuGet packages missing README on nuget.org —
PackageReadmeFilecondition blocked by MSBuild import order, andPackagePathused backslash instead of forward slash
- Core SDK (
Restate.Sdk) with full context hierarchy:Context,ObjectContext,SharedObjectContext,WorkflowContext,SharedWorkflowContext - Context interfaces:
IContext,ISharedObjectContext,IObjectContext,ISharedWorkflowContext,IWorkflowContextfor utility methods, type constraints, and documentation - Service types:
[Service],[VirtualObject],[Workflow] - Handler attributes:
[Handler],[SharedHandler]with handler-level configuration viaHandlerAttributeBase - Durable execution primitives:
Run,RunAsync,Sleep,After - Service-to-service communication:
Call,CallFuture,Sendwith typed clients - State management:
Get,Set,Clear,ClearAll,StateKeysviaStateKey<T> - Awakeable support:
Awakeable,ResolveAwakeable,RejectAwakeable - Workflow promises:
Promise,PeekPromise,ResolvePromise,RejectPromise - Invocation tracking:
Attach,GetInvocationOutput - Durable future combinators:
IDurableFuture<T>,All,Race,WaitAll - Deterministic utilities:
DurableRandom,Now() - Replay-aware logging:
DurableConsolewithReplayAwareInterpolatedStringHandler - Ingress client (
RestateClient) for external service invocation - Source generator (
Restate.Sdk.Generators) bundled into Restate.Sdk NuGet package (no separate install needed) - Source generator diagnostics: RESTATE001-009, including compile-time TimeSpan validation (RESTATE009)
- Source generator hardening:
#pragma warning disableon generated code, null checks in deserializers - Testing package (
Restate.Sdk.Testing) withMockContext,MockObjectContext,MockWorkflowContext,MockSharedObjectContext,MockSharedWorkflowContext - Testing features: deterministic
CurrentTime,SetupCallFailure(),RegisterClient<T>(), call/send/sleep recording - AWS Lambda adapter (
Restate.Sdk.Lambda) withRestateLambdaHandler - ASP.NET Core integration:
AddRestate()/MapRestate()DI extensions - Quick-start host:
RestateHost.CreateBuilder() - Native AOT and trimming compatibility (
IsAotCompatible,IsTrimmable) - Per-package NuGet descriptions for Testing and Lambda packages
- Pack verification in CI pipeline (validates generator bundling on every PR)
- Version validation in publish workflow (tag must match Directory.Build.props)
- GitHub Release creation on tag push
- Release process guide (RELEASING.md)
- 4 sample applications: Greeter, Counter, TicketReservation, SignupWorkflow
- BenchmarkDotNet microbenchmarks for protocol layer and serialization
- Community files: CONTRIBUTING.md, DECISION_LOG.md, issue templates, CodeQL, Dependabot
- Protocol layer hang caused by incorrect
PipeReader.AdvanceTo(consumed, buffer.End)— fixed toAdvanceTo(consumed) ProposeRunCompletionencoding: raw bytes instead of nested ValueCallCompletion/CallInvocationIdCompletionIDs were swapped (0x800D/0x800E)- PipeReader cleanup race condition in InvocationHandler (await incoming task before completing reader)
RunOptionsstruct (was empty, never used by the protocol layer)