PulseTrade.Comm.GW 1.0.0-beta1

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

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 a GatewayRoute to 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:

  1. Validate the persisted consumer completion against the ticket route, ticket id, and correlation.
  2. Write the terminal task result, failure, or cancellation through CompleteTaskAsync, FailTaskAsync, or CancelTaskAsync.
  3. Notify live waiters only after the terminal task status is persisted.
  4. Send ConsumerController.Confirmed.Instance to the live ConfirmTo actor 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:

  • GatewayDeliveryProducerSaveSnapshotCommand
  • GatewayShardingDeliveryProducerSaveSnapshotCommand

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 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
1.0.0-beta1 0 6/21/2026