PulseTrade.Comm.GW
1.0.0-beta1
dotnet add package PulseTrade.Comm.GW --version 1.0.0-beta1
NuGet\Install-Package PulseTrade.Comm.GW -Version 1.0.0-beta1
<PackageReference Include="PulseTrade.Comm.GW" Version="1.0.0-beta1" />
<PackageVersion Include="PulseTrade.Comm.GW" Version="1.0.0-beta1" />
<PackageReference Include="PulseTrade.Comm.GW" />
paket add PulseTrade.Comm.GW --version 1.0.0-beta1
#r "nuget: PulseTrade.Comm.GW, 1.0.0-beta1"
#:package PulseTrade.Comm.GW@1.0.0-beta1
#addin nuget:?package=PulseTrade.Comm.GW&version=1.0.0-beta1&prerelease
#tool nuget:?package=PulseTrade.Comm.GW&version=1.0.0-beta1&prerelease
PulseTrade.Comm.GW
PulseTrade.Comm.GW is the durable facade package for Generic Gateway hosts. It is intended to be used by a host process that owns HTTP/MCP routes and forwards accepted work into an actor/fabric backend with durable task tickets.
This package deliberately keeps the public durable DTOs Akka-free where they cross the route/task-store boundary. Akka actors, controller refs, and remoting addresses belong to the host/adapter layer, not to persisted task status.
Public Contract
Core DTOs:
GatewayDurableRoute: binds aGatewayRouteto delivery mode, task policy, deduplication, and entity-id strategy.GatewayTaskTicket: public ticket returned to callers when work is accepted.GatewayTaskStatus: append-only status row for accepted/running/completed/failed/cancelled work.GatewayTaskResult: completed result cell stored with the task status.GatewayTaskStore: durable store boundary used by JSONL/production stores.GatewayTaskRecoveryDispatchPlan: side-effect-free recovery plan for accepted/running work.
Persisted task status may contain safe command metadata and a GatewayCell<string> command payload. It must not contain IActorRef, raw Akka address objects, bearer tokens, PATs, OAuth secrets, or HTTP/WebSocket response objects.
Minimal Route Sample
let route =
GatewayRoute.create
(GatewayRouteKey.webApi "POST" "/ttc" "ttc")
(ActorRoute "pingpong")
(GatewaySchema.json "ttc-input" [])
(GatewaySchema.json "ttc-output" [ "result" ])
handlerIn
handlerOut
let durableRoute =
GatewayDurableRoute.create
route
NonShardedDelivery
GatewayTaskPolicy.defaultLongRunning
let registered =
runtime.RegisterRoute durableRoute
handlerIn converts public input into a GatewayCell<string> command cell. handlerOut converts a completed result cell into the public response shape.
Route-Level Task Identity
By default, task identity is read from JSON fields such as taskId, operationId, and idempotencyKey. A route can override those field names without replacing the global runtime resolver:
let identityPolicy =
GatewayTaskIdentityPolicy.create
[ "jobKey" ]
[ "phaseKey" ]
[ "routeIdempotency" ]
let durableRoute =
GatewayDurableRoute.create route NonShardedDelivery GatewayTaskPolicy.defaultShortRequest
|> GatewayDurableRoute.withTaskIdentityPolicy identityPolicy
The runtime applies this policy before handlerIn, so repeated requests with the same route-level identity can return the stored task result without recomputing backend work.
Task-Ticket Sample
let! spawned =
runtime.SpawnTaskAsync route.Key (box inputJson) cancellationToken
match spawned with
| Ok ticket ->
// Return ticket.TicketId to the caller.
()
| Error failure ->
// Project failure with GatewayDurableProjection.
()
A host or recovery worker later dispatches accepted/running tasks:
let! singleTicketPlan =
runtime.PlanTaskDispatchAsync ticket cancellationToken
let! report =
runtime.RedeliverOpenTasksAsync cancellationToken
PlanTaskDispatchAsync is the preferred immediate post-spawn seam for durable controller integration: it plans only the requested ticket, keeps the persisted command cell, and can be bound to producer controller handoff without sweeping the entire task store.
Callers query by ticket id:
let! status =
runtime.QueryTaskByTicketIdAsync ticketId cancellationToken
Controller Result Binding
Host/controller loops should not reimplement task-result persistence, live waiter notification, or delivery confirmation ordering. Use GatewayControllerResultBinding for direct backend completions:
let! completed =
GatewayControllerResultBinding.complete
runtime
ticket
resultCell
cancellationToken
When the backend completion comes from a persistent ConsumerController actor, use GatewayControllerResultLifecycle.applyPersistedConsumerCompletion or GatewayControllerResultConfirmBinding.applyPersistedConsumerCompletionAndConfirm.
let! outcome =
GatewayControllerResultConfirmBinding.applyPersistedConsumerCompletionAndConfirm
runtime
ticket
persistedReply
confirmTo
cancellationToken
The required package-level sequence is result before delivery confirm:
- Validate the persisted consumer completion against the ticket route, ticket id, and correlation.
- Write the terminal task result, failure, or cancellation through
CompleteTaskAsync,FailTaskAsync, orCancelTaskAsync. - Notify live waiters only after the terminal task status is persisted.
- Send
ConsumerController.Confirmed.Instanceto the liveConfirmToactor only after steps 1-3 succeed.
ConfirmTo is a process-local Akka handle. It must never be stored in GatewayTaskStatus, task command metadata, JSONL task stores, task result vaults, or README examples. Recovery redelivers durable command cells and task tickets; it must not replay previous ConsumerController.Confirmed sends or any public HTTP/MCP/WebSocket response side effects.
Actor-owned hosts that let GatewayConsumerActor retain the volatile ConfirmTo handle can set:
let settings =
GatewayConsumerActorSettings.create routeKey persistenceId clock
|> GatewayConsumerActorSettings.withControllerConfirmMode ExternalControllerResultBinding
In ExternalControllerResultBinding mode, the consumer actor persists ConsumerProcessingCompleted and returns a confirm-ready plan, but it does not send ConsumerController.Confirmed.Instance by itself. The host must first call GatewayControllerResultLifecycle.applyPersistedConsumerCompletion; after that succeeds, send GatewayConsumerExternalConfirmCommand back to the same consumer actor. The actor then sends ConsumerController.Confirmed.Instance to its retained live ConfirmTo and replies with GatewayConsumerExternalConfirmReply.
Recovery Rule
Recovery must redeliver command cells to the backend/fabric. It must not replay HTTP responses, WebSocket sends, browser redirects, or MCP JSON-RPC side effects. PlanRecoveryDispatchAsync exists so hosts can inspect dispatchable open tasks without triggering backend work.
Use GatewayStartupRecoveryWorker.executeOnce when the host owns the producer outbox event store and can persist enqueue/attempt events before handoff. Use GatewayStartupRecoveryActorWorker.executeNonShardedOnce when the package GatewayDeliveryProducerActor owns outbox persistence; that helper validates recovery input, sends GatewayDeliveryProducerDispatchCommand to the route producer actor, and treats GatewayDeliveryProducerDispatchAccepted as the startup handoff success boundary. The first actor-owned helper is intentionally non-sharded only.
Producer actors expose explicit outbox snapshot commands for host maintenance loops:
GatewayDeliveryProducerSaveSnapshotCommandGatewayShardingDeliveryProducerSaveSnapshotCommand
These commands save a GatewayProducerOutboxSnapshot containing the actor-owned outbox state and safe counts. Snapshot payloads are actor/runtime state, not public request/response side effects.
Store Rule
The first built-in task store is GatewayJsonlTaskStore. The first built-in result payload store is GatewayFileResultVaultStore, exposed through the GatewayResultVaultStore contract and attached with GatewayDurableRuntimeConfig.withResultVaultStore.
CompleteTaskAsync writes the result vault before terminal task status. QueryTaskResultByTicketIdAsync, WaitForTaskResultAsync, and task-centric retry paths can hydrate a completed status whose embedded result payload was compacted away. If neither the status nor the configured vault has the result, the runtime returns result-vault-missing instead of rerunning handlerIn or the backend.
Production hosts may replace both stores with SQL/PCSL-backed stores, but the same DTO rule remains: task status and result vault records are command/result data, not live actor handles.
Solution and Package Boundary
The facade project is expected to stay visible from the root PulseTrade.fs.sln. Consumers should reference PulseTrade.Comm.GW when they need the durable facade APIs; lower packages remain available for hosts that only need the Akka-free contracts or ASP.NET shell.
The NuGet package must carry an explicit PackageId, description, tags, and this README. Release publishing is a separate approved operation; local pack/build validation must not be treated as NuGet push approval.
| Product | Versions 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. |
-
net10.0
- Akka (>= 1.5.69)
- Akka.Cluster (>= 1.5.69)
- Akka.Cluster.Sharding (>= 1.5.69)
- Akka.Persistence (>= 1.5.69)
- FAkka.FCell2 (>= 10.1.300)
- FSharp.Core (>= 10.1.301)
- PulseTrade.Comm.GW.Abstractions (>= 1.0.0-beta1)
- PulseTrade.Comm.GW.AspNetCore (>= 1.0.0-beta1)
- PulseTrade.Comm.GW.Core (>= 1.0.0-beta1)
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 |
|---|---|---|
| 1.0.0-beta1 | 0 | 6/21/2026 |