OmniRelay is the .NET port of Uber's YARPC runtime, layered on top of Hugo concurrency primitives. It targets transport, middleware, and tooling parity with yarpc-go while embracing .NET idioms (Generic Host, System.CommandLine, Roslyn generators).
Namespaces live under
OmniRelay.*. NuGet packages, tooling, and assemblies publish asOmniRelay.*.
- Transports + codecs: HTTP and gRPC transports covering unary, oneway, and server/client/duplex streaming with JSON, Protobuf, and raw codecs registered through the dispatcher.
- Middleware: Logging, tracing, metrics, deadlines, retries, panic recovery, rate limiting, and peer-circuit breakers applied uniformly across every RPC shape.
- Peer + routing layer: Round-robin, fewest-pending, and two-random-choice choosers; chaos labs; sharding helpers (
ShardedResourceLeaseReplicator,BackpressureAwareRateLimiter) to segment workloads per tenant/resource. - ResourceLease mesh: Resource-neutral
ResourceLease*contracts, SafeTaskQueue dispatcher component, durable replicators (SQLite, gRPC, object storage), deterministic state stores (SQLite/FileSystem with Cosmos/Redis guidance), control-plane endpoints, and failure drills. Seedocs/architecture/omnirelay-rpc-mesh.md. - Diagnostics + observability:
/omnirelay/introspect,/healthz,/readyz, runtime tracing/logging toggles, Prometheus + OTLP exporters, mesh health dashboard guidance, and governance-ready replication sinks. - Tooling:
omnirelayCLI, source-generated configuration loading, and automation scripts for drain/restore/upgrade flows. - Code generation: Protobuf
protocplug-in + Roslyn incremental generator emitting typed OmniRelay clients and dispatcher registration helpers. - CI status: Active backlog lives in
todo.md; new work focuses on conformance harnesses and expanded sample coverage.
src/OmniRelay- buildsOmniRelay.dll; contains dispatcher, transports, codecs, middleware, peer subsystem, and client helpers.src/OmniRelay.Cli- builds theOmniRelay.Cliglobal tool (omnirelaycommand) for config validation, introspection, and scripted smoke tests.src/OmniRelay.Codegen.Protobuf- builds theOmniRelay.Codegen.Protobufconsole plug-in (protoc-gen-omnirelay-csharp).src/OmniRelay.Codegen.Protobuf.Generator- Roslyn incremental generator package (ships OmniRelay runtime dependencies).tests/OmniRelay.Core.UnitTests- xUnit coverage across transports, middleware, peer logic, codecs, configuration, and codegen.tests/OmniRelay.YabInterop- yab-driven HTTP/gRPC interop harness.docs/- architecture plan, backlog, and reference guides (streaming, middleware, diagnostics, shadowing, etc.).
dotnet build OmniRelay.slnx
dotnet test tests/OmniRelay.Core.UnitTests/OmniRelay.Core.UnitTests.csprojOmniRelay targets .NET 10 and pulls Hugo, gRPC, and JsonSchema.Net from NuGet. Tests expect loopback HTTP/2 support for gRPC scenarios.
Use the Docker CI recipe to match the pipeline’s restore/build/test steps:
./eng/run-ci.sh --build-arg DOTNET_VERSION=10.0.100Pass any additional docker build flags after the script (for example, --progress=plain).
Add --arch x64 or --arch arm64 to force the platform (defaults to your host).
Docker logging levels map to docker build --progress=<level>:
auto(default) – Docker chooses between TTY/plain depending on the terminal.plain– line-oriented logs, useful for CI and truncation-free output.tty– interactive TTY view with live-updating build steps.
OmniRelay is AOT-first for cloud-native deployments. Run the shared helper to produce native binaries (defaults to linux-x64):
./eng/run-aot-publish.sh
./eng/run-aot-publish.sh linux-arm64 ReleaseSee docs/architecture/aot-guidelines.md for trimming guidance, contributor expectations, and troubleshooting tips.
Use the hyperscale CI Dockerfile to run feature/integration/hyperscale suites in a controlled container:
docker build -f docker/Dockerfile.hyperscale.ci .Internally it calls eng/run-hyperscale-smoke.sh, which executes the representative chaos/diagnostics suites to validate control-plane readiness.
The legacy samples/ tree has been removed while we refresh the runtime for Native AOT and source-generated configuration. New sample hosts will return once the refreshed setup is stable; refer to the hosting examples below in the interim.
using System;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using OmniRelay.Core;
using OmniRelay.Core.Middleware;
using OmniRelay.Dispatcher;
using OmniRelay.Transport.Http;
using OmniRelay.Transport.Grpc;
using static Hugo.Go;
public record PostLedgerEntryRequest(string AccountId, decimal Amount);
public record AckResponse(string Status);
var options = new DispatcherOptions("ledger");
// Inbounds expose HTTP and gRPC entry points plus health endpoints.
options.AddLifecycle("http-inbound", new HttpInbound(new[] { "http://0.0.0.0:8080" }));
options.AddLifecycle("grpc-inbound", new GrpcInbound(new[] { "http://0.0.0.0:9090" }));
// Outbounds can mix transports; gRPC automatically load-balances peers.
options.AddUnaryOutbound(
"payments",
null,
new GrpcOutbound(new[] { new Uri("http://payments-grpc:9090") }, "payments"));
options.AddOnewayOutbound(
"audit",
null,
HttpOutbound.Create(
new HttpClient { BaseAddress = new Uri("http://audit:8080") },
requestUri: new Uri("http://audit:8080/yarpc/v1/billing::record"))
.ValueOrThrow());
// Global middleware applies to every procedure; builders layer per-procedure middleware.
options.UnaryInboundMiddleware.Add(new RpcTracingMiddleware());
options.UnaryInboundMiddleware.Add(new RpcMetricsMiddleware());
var dispatcher = new Dispatcher(options);
var codec = new JsonCodec<PostLedgerEntryRequest, AckResponse>();
dispatcher.RegisterUnary(
"ledger::post-entry",
builder => builder
.WithEncoding(codec.Encoding)
.Handle(async (request, ct) =>
{
var decode = codec.DecodeRequest(request.Body, request.Meta);
if (decode.IsFailure)
{
return Err<Response<ReadOnlyMemory<byte>>>(decode.Error!);
}
// Apply domain logic (omitted)
await Task.CompletedTask.ConfigureAwait(false);
var responseMeta = new ResponseMeta(encoding: codec.Encoding);
var encode = codec.EncodeResponse(new AckResponse("ok"), responseMeta);
if (encode.IsFailure)
{
return Err<Response<ReadOnlyMemory<byte>>>(encode.Error!);
}
return Ok(Response<ReadOnlyMemory<byte>>.Create(new ReadOnlyMemory<byte>(encode.Value), responseMeta));
}));
await dispatcher.StartAsync();
// ...
await dispatcher.StopAsync();The HTTP inbound exposes /omnirelay/introspect, /healthz, and /readyz. Introspection snapshots list procedures, middleware stacks, codec aliases, transport diagnostics (including tee/shadow metadata), and per-peer metrics.
Configuration-driven hosting now uses trimming-safe, source-generated binding. Point AddOmniRelayDispatcherFromConfig("appsettings.dispatcher.json") at a dispatcher JSON payload and register any custom middleware/interceptors in DI. Updated samples will land after the ongoing AOT refactor.
omnirelay config validate --config appsettings.json --config appsettings.Development.jsonomnirelay introspect --url http://127.0.0.1:8080/omnirelay/introspect --format textomnirelay request --transport grpc --address http://127.0.0.1:9090 --service echo --procedure Ping --profile protobuf:echo.EchoRequest --proto-file descriptors/echo.protoset --body '{"message":"cli"}'omnirelay benchmark --transport http --url http://127.0.0.1:8080/yarpc/v1 --service echo --procedure echo::ping --profile json:pretty --body '{"message":"load"}' --concurrency 20 --requests 500omnirelay script run --file docs/reference/cli-scripts/echo-harness.json --dry-run
Install locally with:
dotnet pack src/OmniRelay.Cli/OmniRelay.Cli.csproj -c Release -o artifacts/cli
dotnet tool install --global OmniRelay.Cli --add-source artifacts/cliSee docs/reference/cli.md for profiles, protobuf automation, and CI recipes.
src/OmniRelay.Codegen.Protobufprovidesprotoc-gen-omnirelay-csharp, which emits dispatcher registration helpers (Register<Service>), service interfaces, and typed OmniRelay clients (unary + streaming) with codecs pre-wired.src/OmniRelay.Codegen.Protobuf.Generatorpackages the same emitter as a Roslyn incremental generator. Reference it as an analyzer, generate descriptor sets viaGrpc.Tools, and add them toAdditionalFilesto light up IntelliSense-friendly clients. Thetests/OmniRelay.Codegen.Testsproject shows the descriptor-set pattern used in CI.
- gRPC transports ship logging, tracing, and metrics interceptors (
GrpcTelemetryOptions) that emit OpenTelemetry-compatibleActivityandMeterdata. - Peer leasing feeds
OmniRelay.Core.Peerscounters and the dispatcher readiness evaluator (/readyz). - Introspection surfaces peer health summaries (success/failure counts, latency percentiles) along with middleware, codec, and tee/shadow wiring. The CLI can print a summary or raw JSON snapshot.
Active backlog lives in todo.md. Near-term focus:
- OpenTelemetry exporter helpers and logging enrichers.
- Sample services demonstrating configuration-driven wiring and middleware composition.
- Cross-language conformance + benchmarking harnesses against
yarpc-go. - CI matrix builds across OS/runtime combinations with analyzer + formatting gates.
docs/reference/index.md- docs index for key topics.docs/architecture/omnirelay-rpc-mesh.md- end-to-end ResourceLease mesh architecture (replication, diagnostics, failure drills).docs/reference/http-transport.md- TLS, proxy placement, SSE behaviour, and tracing guidance for the HTTP transport.docs/reference/http3-developer-guide.md- enabling HTTP/3 locally and in staging/production with prerequisites and troubleshooting.docs/reference/http3-faq.md- HTTP/3/QUIC troubleshooting FAQ (ALPN, UDP, macOS, curl, etc.).docs/reference/streaming.md- unary/server/client/duplex streaming guidance.docs/reference/middleware.md- composition rules and builder APIs.docs/reference/errors.md- status mapping, adapters, and fault helpers.docs/reference/shadowing.md- tee/shadow outbounds and sampling controls.docs/reference/grpc-compatibility.md- current status of gRPC client HTTP/3 support across languages.
Contributions welcome - capture findings in todo.md or open an issue when new gaps surface.
