Concepts
The vocabulary used across the platform. Each section is a survey — the formal definition lives in the OpenSpec.
gRPC (mirrored invocation)
gRPC is the inter-service wire protocol. Every
backend service exposes a gRPC interface; the
API gateway discovers that
interface via gRPC reflection
and proxies calls to it. Clients do not need the backend's .proto
files at compile time — they call by service and method name
through the gateway.
- Why Virtufin uses it: one wire protocol for all backends, one client library per language, streaming for free, native integration with the reflection-based gateway.
- See Cross-cutting spec for the platform-wide rules.
Dapr
Dapr is the sidecar that Virtufin uses for pub/sub, state, and service-to-service invocation. The Virtufin services do not talk to NATS / Redis / a KV store directly — they talk to Dapr, and Dapr talks to the backend. This is why the API gateway can swap brokers without changes to the calling code.
- Why Virtufin uses it: portable infra (Dapr runs on K8s,
docker compose, bare metal, and a sidecar-less in-process mode), one API for pub/sub + state + service invocation, and no bespoke SDK per language. - See Cross-cutting spec.
Pub/Sub (CloudEvents 1.0)
All inter-service events are
CloudEvents 1.0 envelopes. Producers
publish via the Pubsub.PublishEvent RPC on the
API gateway; consumers
subscribe via Pubsub.Subscribe (server-streaming) or
Pubsub.PublishEvent (with a response_topic for request/response
patterns). The gateway is the only service that talks to the
Dapr pub/sub directly.
- Why Virtufin uses it: CloudEvents is the lingua franca for
event metadata (
source,type,subject,time), CloudEvents 1.0 has implementations in every target language, and routing once-type+subjectis the unit of subscription. - See pubsub-topics spec for the topic naming scheme.
Lanes & scenarios (event routing)
Two orthogonal axes split the event stream into addressable topics:
- Market-data lane —
act.exchange.<venue>.<entity>.<event>[.<id>]for live data,hyp.<selector>.exchange.<venue>.<entity>.<event>[.<id>]for historical replays. - Scenario lane —
sc.<scenarioId>.<domain>.<entity>.<event>[.<id>]for strategy / position / P&L / risk events that depend on a triplet of (market data, portfolio, strategy) state.
The reserved scenario id LIVE is the production scenario and
is auto-seeded at service start with the {act, act, act}
triplet. A backtest registers its own scenario id and replays the
same market data stream with a different time clock.
- Why Virtufin uses it: the same producer code can target production and backtest by changing one address. A new selector (a new data universe) is a topic addition, not a code change.
- See pubsub-topics spec and scenarios spec.
State (distributed KV)
State is a flat key-value store, partitioned by service name. The
State.* RPCs on the API gateway
are the only interface; each service sees its own namespace
(State.SaveState(service: "websocketmanager", ...)). The
gateway handles ETag-based conflict detection and forwards to
Dapr's state API.
- Why Virtufin uses it: services do not own storage. The gateway's state is a generic KV; the Dapr sidecar talks to whatever backing store is configured (Redis, Cosmos, Postgres, in-memory for tests).
- See Cross-cutting spec.
Workers
A worker is a piece of code that subscribes to events (or accepts commands) and produces events back. The WorkManager loads workers via pluggable engines and dispatches incoming events to them. The wire protocol is fixed by the worker-management spec.
- Why Virtufin uses it: strategy code is a unit of deployment, not a service. A new strategy does not require a new gRPC service, a new proto, or a new deploy. It is a file in a workers repo, loaded at startup.
- See Worker DevKit for the writing side.
Engines
An engine is the loader. The WorkManager supports four:
| MIME type | Engine | Process model |
|---|---|---|
text/x-csharp |
CSharpSourceEngine |
in-process (Roslyn compile) |
application/x-dotnet-dll |
DotNetDllEngine |
in-process (CoreCLR via libhostfxr) |
text/x-python |
PythonEngine |
out-of-process subprocess |
application/x-native-dll |
NativeDllEngine |
in-process (C/C++/Rust shared library) |
- Why Virtufin uses it: the strategy language is a choice for the strategy author, not a constraint of the platform. In-process is the default because it has the lowest latency and the simplest deploy.
- See engines spec.
NativeAOT
The .NET services (virtufin-api, virtufin-websocketmanager,
virtufin-workmanager) are compiled to native binaries with
NativeAOT.
No JIT, no runtime install, no warm-up.
- Why Virtufin uses it: consistent resource profile with the Python and native workers, sub-100ms cold start for autoscaling, fewer moving parts in production.
- See Cross-cutting spec.
CloudEvents 1.0 (envelope)
The wire format for every event. The Virtufin-specific extensions
live in the same envelope: correlationid, scenarioid, runid,
exchange, clocktype (wall / historical), eventtime,
walltime, market.lane, market.selector, portfolio.lane,
strategy.lane.
- Why Virtufin uses it: the metadata is the contract. A
consumer can route on
clocktype=historicalto filter out production-only paths, or onscenarioid=backtest-42to isolate a single backtest's outputs. - See pubsub-topics spec.