Release v0.0.44-50
Overview
This release consolidates seven interim versions (v0.0.44 through v0.0.49) into the stable v0.0.50 release. The primary themes are pipeline correctness, infrastructure resilience, performance optimization, and observability.
On the correctness front, workflow timeout now executes the full TransitionPipeline (onExit, onEntry, automatic transitions, finish handling) instead of a direct state mutation, and the async execution race condition that prematurely set instances to Active before post-commit jobs completed has been resolved. Extension error handling is reclassified so that infrastructure failures abort the request while application-level errors degrade gracefully. Schema validation is now enforced on sync=false requests, preventing invalid payloads from being accepted and later faulting.
Infrastructure improvements include UTC DateTime normalization via an EF Core interceptor and global ValueConverter (independent of PostgreSQL server timezone), a PgBouncer-safe schema command interceptor replacing the connection-level interceptor, and a timestamp with time zone migration for SubFlowStateChangedAt. On the CI/CD side, software supply chain security (Cosign signing, provenance attestation) and a cross-repo dispatch token fix strengthen the delivery pipeline.
Performance gains come from distributed cache tracing with short-TTL local vidx caching (eliminating redundant Redis roundtrips), broadcast cache invalidation that reads from distributed cache instead of performing a full DB reload on non-initiating pods, and hot-path index adjustments that fix a GetInstanceHistory regression and remove a redundant partial PK index.
New capabilities include dynamic workflow timeout mapping via ITimerMapping scripts (with static duration fallback), ErrorBoundary enrichment with errorMessage, errorState, and errorTask parameters in instance data, acceptedStatusCodes on HTTP-based task types to suppress ErrorBoundary for expected non-2xx responses, and local/remote metadata parity for GetInstances and GetInstanceData task executors.
Bug Fixes
Timeout target state pipeline not executed (#514)
When a workflow instance timed out, FlowTimeoutJobHandler changed the instance state and marked it complete but never ran the TransitionPipeline. All onExit tasks, onEntry tasks, automatic transitions, scheduled transitions, and finish-state handling were silently skipped. The handler now invokes the full TransitionPipeline with a synthetic timeout transition context, ensuring consistent state lifecycle execution regardless of how a transition is triggered.
Reference: #514
Extension failures abort the entire request (#515)
On all InstanceData read endpoints, any extension task failure caused the entire HTTP response to be aborted — even when the extension's outputMapping had already handled the downstream error at the application level. Error classification is now split into two categories:
- Infrastructure errors (network timeout, DNS failure, connection refused) — fail-fast, abort request.
- Application-level / output-mapping-handled errors — degrade gracefully, continue with remaining extensions.
Reference: #515
UTC DateTime normalization (#520)
PostgreSQL server configured with TimeZone = 'Europe/Istanbul' caused silent +3h offset corruption on all DateTime values stored in timestamp (without time zone) columns. A two-layer defense-in-depth fix was implemented:
- Write path:
UtcDateTimeInterceptor(SaveChangesInterceptor) normalizes allDateTimeproperties to UTC beforeSaveChanges. - Read path: Global
UtcDateTimeConverterviaConfigureConventionsensures allDateTimevalues read from the database are tagged asDateTimeKind.Utc.
Behavior is now independent of the PostgreSQL server timezone configuration.
Reference: #520
SubFlowStateChangedAt timestamp migration (#525)
The SubFlowStateChangedAt column in InstancesCorrelations was timestamp without time zone. A migration converts it to timestamp with time zone using AT TIME ZONE 'UTC', aligning it with the rest of the schema.
Reference: #525
PgBouncer-safe schema interceptor (#534)
NpgsqlSchemaConnectionInterceptor set search_path at connection open time, which PgBouncer transaction-mode pooling could reassign to a different session. The new PgBouncerSafeSchemaCommandInterceptor prepends SET search_path inline to every SQL command, eliminating the extra round-trip and ensuring schema consistency under pooled connections.
Reference: #534
Async mode race condition: premature Active status (#535)
When sync=false, ResolveAvailableStep and ClearBusyOnResumeStep wrote Active status to the database mid-pipeline, before post-commit jobs (SubFlow start, remote task invocations) had completed. Clients polling during this window would see Active while the pipeline was still executing. The status update is now deferred via PipelineDirectives.SetResolvedStatus and applied in TransitionPipeline.ApplyResolvedStatusAsync only after all post-commit jobs complete.
Reference: #535
Cross-repo dispatch token scope (#541)
The actions/create-github-app-token step generated a token scoped only to vnext. peter-evans/repository-dispatch targeting vnext-helm-charts failed with HTTP 403. The token scope now includes both repositories.
Reference: #541
Schema validation skipped on sync=false (#556)
When sync=false, the async strategy accepted any payload without validating against the transition's JSON schema. Invalid data entered the system and faulted during background execution. Schema validation is now performed before accepting the request, regardless of the sync flag. Invalid payloads return 400 Bad Request with field-level errors.
Reference: #556
Local execution metadata parity for GetInstances / GetInstanceData (#563)
GetInstanceDataTaskExecutor.ExecuteLocalAsync returned no metadata on the happy path, and GetInstancesTaskExecutor had inconsistent metadata between local and remote paths. Both executors now build and return the same metadata dictionary as the remote/grouped paths, ensuring downstream consumers (scripting, mapping, logging) see identical shapes regardless of execution mode.
Reference: #563
Features & Enhancements
ErrorBoundary enrichment: error message, state, task parameters (#496)
ErrorBoundary now populates errorMessage, errorState, and errorTask fields in instance data when an error is caught. This enables downstream consumers (backoffice UIs, mapping scripts) to display meaningful error context and handle errors programmatically.
Reference: #496
Dynamic timeout mapping for subprocesses (#524)
Workflow-level timeout now supports an optional mapping field (a ScriptCode object implementing ITimerMapping) for dynamic timeout duration calculation at runtime. When the mapping script succeeds, its TimerSchedule result is used. On failure, the static timer.duration is used as fallback. A static timer configuration is required when mapping is defined (validation enforced).
Definition example:
"timeout": {
"key": "$timeout",
"target": "timed-out",
"versionStrategy": "None",
"timer": { "reset": "false", "duration": "PT1H" },
"mapping": {
"location": "./src/TimeoutMapping.csx",
"code": "<BASE64>"
}
}
Use case: A parent workflow starts a subprocess with timeoutMinutes: 30 in the body. The subprocess timeout mapping reads this value and schedules a 30-minute timeout. If the mapping fails, the static 1-hour fallback applies.
Documentation: Transitions, Workflow Definition
Reference: #524
Task acceptedStatusCodes configuration (v0.0.50+)
HTTP-based task types now support an optional acceptedStatusCodes array in their config section. Status codes listed here are treated as successful even when they are error codes (4xx, 5xx), preventing the ErrorBoundary from being triggered. Supports exact codes ("404"), wildcard patterns ("4xx"), and partial wildcards ("40x").
Supported task types: Dapr Service (3), HTTP (6), StartTask (11), DirectTriggerTask (12), GetInstanceDataTask (13), SubProcessTask (14), GetInstances (15).
"config": {
"method": "GET",
"url": "http://user-service/api/users/{userId}",
"acceptedStatusCodes": ["404"]
}
Documentation: HTTP Task, Dapr Service Task, Trigger Tasks
Software supply chain security (#545)
The CI/CD pipeline now produces verifiable, signed, and traceable container images:
- Digest-based image handling for immutable references
- Cosign keyless signing with GitHub OIDC for artifact authenticity
- Build provenance attestation via GitHub attestation actions
- Ready for downstream admission-policy verification
Reference: #545
Performance Improvements
Broadcast cache invalidation: distributed-cache-first reload (#557)
Non-initiating pods receiving a DefinitionCacheInvalidationEvent broadcast no longer perform a full paginated DB read of all active instance data. Instead, they read instance metadata (keys/versions), check the distributed cache first (which the initiating pod has already populated), and upsert only into the local in-memory cache. A per-key DB fallback handles distributed cache misses. This eliminates the heavy, redundant DB round-trip that stalled the first pod receiving the broadcast.
Reference: #557
Distributed cache tracing and Redis vidx optimization (#568)
- Cache tracing: A new
CacheActivityHelper(ActivitySource("BBT.Workflow.Cache")) wraps distributed cache operations (Cache.Get,Cache.Set,Cache.Remove,Cache.Warmup,Cache.VersionIndex) with proper parent spans so Dapr sidecar spans nest correctly in trace tools. - vidx short-TTL local cache:
CacheSetnow caches Redis version-index (vidx) query results in aConcurrentDictionarywith a short TTL, eliminating 3–5+ redundant Redis roundtrips per transition hop. The local cache is invalidated onSetAsyncandInvalidateAsync.
Reference: #568
Hot-path index adjustments and GetInstanceHistory fix (#561)
- Dropped redundant
IX_Instances_Active_Idpartial PK index (never used by the planner, only write overhead). - Added non-partial
IX_Instances_KeyB-tree forFindByIdentifierAsynckey-based lookups across all statuses. - Fixed
GetInstanceHistoryregression: a newFindByIdentifierWithFullHistoryAsyncrepository method loads the fullDataListwithout theIsLatestfilter, restoring complete revision history on the history endpoint.
Reference: #561
Breaking Changes
None for this release.
Configuration Updates
Configuration for v0.0.50:
{
"runtimeVersion": "0.0.50",
"schemaVersion": "0.0.41"
}
Note: Schema package 0.0.50 is the documented pairing with this runtime. The
task-definition.schema.jsonandworkflow-definition.schema.jsoninclude new fields (acceptedStatusCodes,timeout.mapping). Update domainvalidate.js/ Ajv2019 usage per Schema Management.
Issues Referenced
- vnext #496 — ErrorBoundary enrichment (error message, state, task)
- vnext #514 — FlowTimeoutJobHandler pipeline execution
- vnext #515 — Extension error classification / graceful degradation
- vnext #520 — UTC DateTime normalization
- vnext #521 — Rejecting out-of-order SubFlow state (duplicate of #520/#525)
- vnext #524 — Dynamic timeout mapping for subprocesses
- vnext #525 — SubFlowStateChangedAt timestamptz migration
- vnext #534 — PgBouncer-safe schema interceptor
- vnext #535 — Async mode race condition (premature Active status)
- vnext #541 — Cross-repo dispatch token scope
- vnext #545 — Software supply chain security
- vnext #556 — Schema validation on sync=false
- vnext #557 — Broadcast cache invalidation optimization
- vnext #561 — Hot-path indexes + GetInstanceHistory fix
- vnext #563 — Local execution metadata parity
- vnext #568 — Distributed cache tracing + vidx optimization
Summary
- Timeout pipeline now executes full
TransitionPipeline(onExit, onEntry, automatic transitions, finish handling) instead of direct state mutation. - Extension error handling reclassified: infrastructure errors fail-fast, application-level errors degrade gracefully.
- UTC DateTime normalization via EF Core interceptor + global ValueConverter, independent of server timezone.
- PgBouncer-safe schema command interceptor replaces connection-level interceptor.
- Async race condition fixed:
Activestatus deferred until all post-commit jobs complete. - Schema validation enforced on
sync=falserequests; invalid payloads rejected with400. - Dynamic timeout mapping via
ITimerMappingscripts with static duration fallback. - ErrorBoundary enrichment with
errorMessage,errorState,errorTaskin instance data. acceptedStatusCodeson HTTP-based tasks to suppress ErrorBoundary for expected non-2xx responses.- Supply chain security: Cosign signing, provenance attestation, digest-based image handling.
- Cache performance: distributed-cache-first broadcast reload, vidx short-TTL local cache, cache operation tracing.
- Index optimization: redundant partial PK dropped, Key index added, GetInstanceHistory regression fixed.
- Metadata parity between local and remote execution paths for GetInstances/GetInstanceData task executors.
vNext Runtime Platform Team April 25, 2026
