Verbara.Sdk.Push
2.8.0
dotnet add package Verbara.Sdk.Push --version 2.8.0
NuGet\Install-Package Verbara.Sdk.Push -Version 2.8.0
<PackageReference Include="Verbara.Sdk.Push" Version="2.8.0" />
<PackageVersion Include="Verbara.Sdk.Push" Version="2.8.0" />
<PackageReference Include="Verbara.Sdk.Push" />
paket add Verbara.Sdk.Push --version 2.8.0
#r "nuget: Verbara.Sdk.Push, 2.8.0"
#:package Verbara.Sdk.Push@2.8.0
#addin nuget:?package=Verbara.Sdk.Push&version=2.8.0
#tool nuget:?package=Verbara.Sdk.Push&version=2.8.0
Verbara.Sdk.Push
Real-time push primitives for .NET. AOT-safe, host-agnostic, MIT licensed.
What it does
- Typed, in-memory event bus (
IPushEventBus) backed by a boundedSystem.Threading.Channels.Channel<T>with configurable backpressure. - Delivery filter (
IEventDeliveryFilter) that enforces tenant isolation and optional per-user targeting before an event reaches a subscriber. - Subscription registry (
ISubscriptionRegistry) for tracking active subscribers per tenant with automatic cleanup on disposal. - First-class diagnostics via
System.Diagnostics.Metrics(meter nameVerbara.Sdk.Push).
No ASP.NET Core dependency. No reflection. Trim-safe.
Install
dotnet add package Verbara.Sdk.Push
Quick start
using Verbara.Sdk.Push.Bus;
using Verbara.Sdk.Push.Delivery;
using Verbara.Sdk.Push.Events;
using Verbara.Sdk.Push.Hosting;
using Verbara.Sdk.Push.Subscriptions;
using Microsoft.Extensions.DependencyInjection;
// 1) Define a concrete event
public sealed record ConversationAssigned : PushEvent
{
public required string ConversationId { get; init; }
public override string EventType => "conversation.assigned";
}
// 2) Register services
var services = new ServiceCollection();
services.AddLogging();
services.AddVerbaraPush(options =>
{
options.BufferCapacity = 512;
options.BackpressureStrategy = BackpressureStrategy.DropOldest;
});
using var sp = services.BuildServiceProvider();
var bus = sp.GetRequiredService<IPushEventBus>();
var filter = sp.GetRequiredService<IEventDeliveryFilter>();
var registry = sp.GetRequiredService<ISubscriptionRegistry>();
// 3) Register a subscriber and subscribe to a typed stream
var subscriber = new SubscriberContext(
TenantId: "tenant-1",
UserId: "user-42",
Roles: new HashSet<string> { "agent" },
Permissions: new HashSet<string> { "conversation:read" });
using var _registration = registry.Register(subscriber);
using var subscription = bus.OfType<ConversationAssigned>().Subscribe(evt =>
{
if (filter.IsDeliverableToSubscriber(evt, subscriber))
{
Console.WriteLine($"{evt.EventType}: {evt.ConversationId}");
}
});
// 4) Publish
await bus.PublishAsync(new ConversationAssigned
{
ConversationId = "c-123",
Metadata = new PushEventMetadata(
TenantId: "tenant-1",
UserId: "user-42",
OccurredAt: DateTimeOffset.UtcNow,
CorrelationId: null),
});
Contract
PushEventBusOptions
| Setting | Default | Description |
|---|---|---|
BufferCapacity |
256 |
Max in-flight events before the backpressure strategy kicks in. Must be >= 1. |
BackpressureStrategy |
DropOldest |
Behavior when the buffer is full. |
BackpressureStrategy
DropOldest(default) — evict the oldest buffered event to make room for the new one. Favors freshness; appropriate for live UI streams where stale events are worthless.DropNewest— evict the most recently buffered event to admit the new one (the BCLDropNewestmode). The oldest buffered events survive; the event being published is always enqueued.Block— await buffer space. Use only when publishers can tolerate backpressure (batch pipelines, not hot request paths).
Every event a full buffer evicts under DropOldest or DropNewest increments asterisk.push.events.dropped once, tagged reason="buffer_full"; Block never evicts. A publish that races the bus's disposal is counted with reason="writer_closed".
Observability
The package exposes a System.Diagnostics.Metrics.Meter named Verbara.Sdk.Push with the following instruments:
| Instrument | Kind | Description |
|---|---|---|
asterisk.push.events.published |
Counter<long> | Events accepted by PublishAsync. |
asterisk.push.events.delivered |
Counter<long> | Events dispatched to at least one observer. |
asterisk.push.events.dropped |
Counter<long> | Events discarded (tag: reason=buffer_full\|writer_closed). |
asterisk.push.sse.events.dropped |
Counter<long> | Event frames an SSE connection of Verbara.Sdk.Push.AspNetCore dropped at its per-connection bound (each reported to that client in a .gap frame). |
asterisk.push.subscribers.active |
ObservableGauge<int> | Current active subscriptions (bound via PushMetrics.BindActiveSubscribersGauge). |
Wire into OpenTelemetry with meterProvider.AddMeter("Verbara.Sdk.Push").
Tracing
The bus also starts spans on an ActivitySource named Verbara.Sdk.Push; register it with
tracerProvider.AddSource("Verbara.Sdk.Push").
Publish.
PublishAsyncstartspush publish <eventType>(Producer) under the publisher's current activity, and records that activity's W3Ctraceparentin the event'sMetadata.TraceContextwhen the publisher left it empty. ATraceContextthe publisher set explicitly is kept as it is.Deliver. The dispatch loop starts
push deliver <eventType>(Internal) as a child of the event'sTraceContext. Every span a subscriber starts while handling the event — a webhook POST's HTTP client span, a NATS publish — is therefore in the publisher's trace, and thetraceparentwritten on the wire (HTTP header, NATS header) belongs to that trace:api.handler (your activity) ├── push publish order.created └── push deliver order.created └── subscriber spans (HTTP POST, NATS publish, …)Root case. An event with no
TraceContext, or one that does not parse as a W3Ctraceparent, is delivered under a rootpush deliverspan, as before; the event is never dropped for it.Who built the bus does not matter. The dispatch loop starts without the constructing code's ambient activity, so a bus first resolved inside a host start-up span or inside the first HTTP request never puts later deliveries in that trace.
Sampling. Because the delivery is now a child of the publisher's span, a parent-based sampler makes the delivery (and the subscriber spans inside it) follow the publisher's sampling decision instead of deciding afresh at a root.
Cost. With no listener on the source, no span is started and the trace context is not parsed.
AOT
This package is Native AOT compatible. The shipping build verifies zero trim warnings (IL2026 / IL2070 / IL2075 / IL3050 / ...) via the repo's AotCanary publish (tools/verify-aot.sh). No reflection, no DataAnnotations runtime validator, no dynamic code.
Relation with Verbara.Sdk.Pro.Push
This package provides in-memory primitives suitable for single-node hosts. For NATS-backed multi-node fan-out in the MIT surface, see Verbara.Sdk.Push.Nats (available since v1.12). For cluster-wide fan-out over Redis pub/sub or Postgres LISTEN/NOTIFY backplanes (neither stores events for replay), advanced authorization, and enterprise observability, see Verbara.Sdk.Pro.Push — both build on top of this package's abstractions, so the contract is forward-compatible.
Links
- Repository: github.com/verbara/Verbara.Sdk
- Parent SDK README: ../../README.md
- Changelog: ../../CHANGELOG.md
Licensed under the MIT License.
| Product | Versions 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. |
-
net10.0
- Microsoft.Extensions.Configuration.Abstractions (>= 10.0.12)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.12)
- Microsoft.Extensions.Diagnostics.HealthChecks (>= 10.0.12)
- Microsoft.Extensions.Hosting.Abstractions (>= 10.0.12)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.12)
- Microsoft.Extensions.Options (>= 10.0.12)
- System.Reactive (>= 7.0.0)
NuGet packages (3)
Showing the top 3 NuGet packages that depend on Verbara.Sdk.Push:
| Package | Downloads |
|---|---|
|
Verbara.Sdk.Push.Webhooks
Verbara.Sdk.Push.Webhooks - outbound HTTP webhook delivery for Verbara.Sdk.Push. Consumes events from the Push bus, matches against WebhookSubscription topic patterns, POSTs with HMAC-SHA256 signature and exponential retry/backoff. AOT-safe. |
|
|
Verbara.Sdk.Push.Nats
Verbara.Sdk.Push.Nats - publishes Push bus events to a NATS subject hierarchy that mirrors the Push topic tree (asterisk.sdk.**). AOT-safe. |
|
|
Verbara.Sdk.Push.AspNetCore
Verbara.Sdk.Push.AspNetCore - SSE push delivery endpoints for ASP.NET Core. Maps IPushEventBus events to Server-Sent Events with topic filtering and JWT authorization. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 2.8.0 | 84 | 10/9/2026 |
| 2.7.0 | 763 | 10/3/2026 |
| 2.6.1 | 486 | 9/30/2026 |
| 2.6.0 | 723 | 9/24/2026 |
| 2.5.3 | 626 | 9/13/2026 |
| 2.5.2 | 285 | 9/13/2026 |
| 2.5.1 | 279 | 9/12/2026 |
| 2.5.0 | 163 | 8/25/2026 |
| 2.4.0 | 1,920 | 7/27/2026 |
| 2.3.2 | 686 | 7/20/2026 |
| 2.3.1 | 334 | 7/14/2026 |
| 2.3.0 | 391 | 7/6/2026 |
| 2.2.1 | 970 | 5/23/2026 |
| 2.2.0 | 183 | 5/20/2026 |
| 2.1.2 | 169 | 5/8/2026 |
| 2.1.1 | 155 | 5/7/2026 |
| 2.1.0 | 152 | 5/7/2026 |
| 2.0.0 | 160 | 5/6/2026 |