Portal Community

Execution Model

A server-side node is a singleton IHostedService that registers itself with the ServerNodeRegistry during StartAsync. It remains in memory for the lifetime of the process. When a workflow reaches a ServerNodeCallNode, the engine resolves the target server node from the registry and dispatches a request to it — no DI scope is opened and no instance is created.


Application Startup
    ├── IHostedService.StartAsync()
    │       ├── Load model / initialise connection pool
    │       └── ServerNodeRegistry.Register(nodeId, this)
    │
    │  [always-on, waiting for requests]
    │
Workflow Execution (per call)
    ├── ServerNodeCallExecutor.ExecuteAsync(ctx)
    │       ├── ServerNodeRegistry.Resolve(nodeId)
    │       └── await serverNode.HandleRequestAsync(request, ct)
    │
    └── Returns NodeExecutionResult to engine
  

Key Characteristics

CharacteristicDetail
DI lifetimeSingleton — one instance for the process lifetime
StateShared across all workflow executions that call this node
ConcurrencyMust be internally thread-safe — multiple workflow executions may call concurrently
Startup costPaid once at process start — amortised over all subsequent calls
TestingRequires integration tests — startup lifecycle must be tested separately from per-call tests
Failure isolationA server node crash can affect the host process; implement defensive error handling

Why Server Nodes Exist

Some AI and infrastructure capabilities have startup costs that make per-request instantiation impractical:

Concurrency is your responsibility: Because a server node is singleton and shared across concurrent workflow calls, you must use thread-safe data structures (ConcurrentDictionary, SemaphoreSlim, Channel<T>) to manage shared state. Unprotected shared mutable state will produce subtle, hard-to-reproduce bugs under load.