Skip to main content

Release v0.0.66

· 5 min read
vNext Team
Burgan Tech Engineering

Overview

This release brings one significant new capability and three targeted fixes. State-level notifications land as a first-class workflow primitive: a state can now declare a notifications array that the runtime enqueues durably after the transition pipeline completes, decoupling notification dispatch from the task pipeline entirely and guaranteeing state data is fully persisted before delivery (#722). Root instance ID propagation threads a stable ancestor identifier through deep subflow chains so that a single search key in Jaeger or structured logs surfaces every span and log line across the full execution graph (#769). Two fixes round out the release: UTF-16 allocation on every buffered request body is eliminated by switching the raw-body contract from string to ReadOnlyMemory<byte> (#773), and a race condition causing EF Core concurrency exceptions when fetching multiple extensions in parallel is resolved by giving each concurrent fetch its own DbContext scope (#771). This bump advances the component schema to 0.0.48.


Features

State-level notifications (#722)

Workflow states can now declare a notifications array directly in their definition. After the transition pipeline finishes and the new state is fully persisted, the platform enqueues each notification entry and processes it durably — independently of onEntries / onExits task lists. This eliminates the race condition in the earlier Notification Task approach where state data could be read before persistence completed.

The Dapr Binding convention is the same as the existing Notification Task (vnext-notification-state). Mapping is implemented via IStateNotificationMapping. An optional rule script gates whether the notification fires; if omitted, it fires unconditionally.

{
"key": "waiting-approval",
"stateType": 2,
"notifications": [
{
"type": 0, // 0 = State (only supported value)
"mapping": {
"type": "L",
"code": "<base64-encoded IStateNotificationMapping script>",
"encoding": "B64"
},
"rule": { // optional — omit to always fire
"type": "L",
"code": "<base64-encoded condition script>",
"encoding": "B64"
}
}
]
}

The type: 0 (State) notification is enqueued after onEntries complete, before the auto-transition check — so the full state lifecycle has settled before the notification is dispatched.

Reference: issue #722 — see also Workflow component → State Notifications and IStateNotificationMapping.

Root instance ID propagation through nested subflow chains (#769)

In deep subflow hierarchies (A → B → C → D), traces and logs previously only carried the immediate parent's instance ID. This made it impossible to find all spans for a root instance with a single Jaeger or log search query.

Each subflow instance now stores root.instance.id in its ExtraProperties at creation time, and the value is propagated via the X-Root-Instance-Id HTTP header on every outbound subflow start call (enabling cross-domain support). The enrichment middleware stamps vnext.root.instance.id as an OTel tag, baggage entry, and log scope property on every request. A single query on the root instance ID now surfaces spans and log lines from the entire execution chain.

  • MetaDataKeys.RootInstanceId = "root.instance.id" — storage key in instance ExtraProperties
  • X-Root-Instance-Id header — forwarded alongside X-Parent-Instance-Id
  • vnext.root.instance.id — OTel tag / baggage name in Jaeger and structured logs
  • On root instances the tag is omitted to avoid redundant fields

Reference: issue #769


Fixes

Eliminate UTF-16 string allocation in RawRequestBodyBufferingMiddleware (#773)

RawRequestBodyBufferingMiddleware previously captured the raw request body as a string (Encoding.UTF8.GetString(...)) even though downstream consumers only need the raw bytes for JWS / mTLS signature verification. On a 5 MB UTF-8 payload this produced a ~10 MB string on every buffered request, adding significant GC pressure under high traffic.

The contract for RawBodyItemsKey is changed from string to ReadOnlyMemory<byte>. Downstream signature-verification consumers now read bytes directly, with no additional byte[] copies introduced.

Reference: issue #773

Fix concurrent DbContext access in parallel extension fetch (#771)

InstanceExtensionService.FetchExtensionsFromReferencesAsync used Task.WhenAll to fetch multiple extension references concurrently against the same scoped DbContext, triggering a fatal InvalidOperationException ("A second operation was started on this context instance before a previous operation completed") on cache miss.

Each parallel fetch now runs inside its own IServiceScopeFactory.CreateAsyncScope() scope, giving it an isolated DbContext. Sequential and single-extension scenarios are unaffected.

Reference: issue #771


Configuration Updates

Configuration for v0.0.66:

{
"runtimeVersion": "0.0.66",
"schemaVersion": "0.0.48"
}

Note: Schema version advances to 0.0.48 (from 0.0.47). The bump adds the notifications array definition on state objects (#722). Update @burgan-tech/vnext-schema in your domain project before validating against this runtime.

Container images: published at tag 0.0.66 under ghcr.io/burgan-tech/vnext/*, Cosign-signed (keyless OIDC) with SBOM + provenance. Immutable digests are listed in the GitHub release.


Issues Referenced

  • vnext #722 — State-level notifications: guaranteed state availability and configurable payload.
  • vnext #769 — Propagate root instance ID through nested subflow chains for log and trace correlation.
  • vnext #773 — Eliminate UTF-16 string allocation in RawRequestBodyBufferingMiddleware.
  • vnext #771 — Fix concurrent DbContext access in parallel extension fetch.

Summary

  • State notifications are now a first-class primitive: declare a notifications array on any state, enqueued durably after the pipeline, with optional conditional rule and IStateNotificationMapping for payload shaping.
  • Root instance ID propagates through nested subflow chains via ExtraProperties, X-Root-Instance-Id header, and vnext.root.instance.id OTel tag — one search key finds the entire execution graph.
  • Performance: raw request body contract changed from string to ReadOnlyMemory<byte>, eliminating a ~10 MB GC allocation per large buffered request.
  • Fix: parallel extension fetch now uses per-scope DbContext to prevent InvalidOperationException on concurrent cache misses.
  • Schema advances to 0.0.48.

vNext Runtime Platform Team
Released June 29, 2026