Flow Studio
Registering Server Nodes
How to register a server node as a hosted service in the DI container — and how the ServerNodeRegistry tracks availability for workflow dispatch.
DI Registration
// In Program.cs / Startup.cs:
builder.Services.AddServerNode<LocalEmbeddingServerNode>(options =>
{
options.NodeId = "local-embedding";
options.DisplayName = "Local Text Embedding Server";
options.ModelPath = builder.Configuration["AI:EmbeddingModelPath"]
?? "/opt/models/bge-small-en-v1.5.onnx";
options.MaxConcurrency = 4;
});
AddServerNode<T> is an extension method that internally does:
public static IServiceCollection AddServerNode<TServerNode>(
this IServiceCollection services,
Action<ServerNodeOptions> configure)
where TServerNode : class, IServerNode
{
services.Configure(configure);
services.AddSingleton<TServerNode>();
services.AddSingleton<IServerNode>(sp => sp.GetRequiredService<TServerNode>());
services.AddHostedService(sp => sp.GetRequiredService<TServerNode>());
return services;
}
ServerNodeRegistry
public interface IServerNodeRegistry
{
void Register(string nodeId, IServerNode node);
void Deregister(string nodeId);
bool TryGetNode(string nodeId, out IServerNode? node);
IReadOnlyCollection<string> RegisteredNodeIds { get; }
}
The registry is a singleton ConcurrentDictionary-backed store. Server nodes call Register at the end of StartAsync and Deregister at the start of StopAsync. The ServerNodeCallExecutor uses TryGetNode to route workflow calls.
Configuration Pattern
// appsettings.json:
{
"ServerNodes": {
"LocalEmbedding": {
"ModelPath": "/opt/models/bge-small-en-v1.5.onnx",
"MaxConcurrency": 4,
"WarmupOnStart": true
}
}
}
// Options class:
public class LocalEmbeddingOptions
{
public string ModelPath { get; set; } = string.Empty;
public int MaxConcurrency { get; set; } = 2;
public bool WarmupOnStart { get; set; } = true;
}
// Registration with configuration binding:
builder.Services.AddServerNode<LocalEmbeddingServerNode>(options =>
builder.Configuration.GetSection("ServerNodes:LocalEmbedding")
.Bind(options));
Health Endpoint
Once registered, each server node is automatically surfaced in the platform health check:
GET /health/server-nodes
{
"nodes": [
{
"nodeId": "local-embedding",
"isReady": true,
"status": "healthy",
"checkedAt": "2026-05-25T10:00:00Z",
"diagnostics": {
"modelLoaded": true,
"activeRequests": 2,
"queueDepth": 0
}
}
]
}
GET /health/server-nodes/local-embedding
{ "nodeId": "local-embedding", "isReady": true, "status": "healthy", ... }
Startup ordering: If a server node depends on another service (e.g., a configuration service that loads the model path from a database), use
IHostedService startup ordering via builder.Services.AddHostedService registration order. Services registered earlier start earlier. The server node that depends on the config service should be registered after it.