Fluens.Web.Messaging.Dashboard 0.7.4

dotnet add package Fluens.Web.Messaging.Dashboard --version 0.7.4
                    
NuGet\Install-Package Fluens.Web.Messaging.Dashboard -Version 0.7.4
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Fluens.Web.Messaging.Dashboard" Version="0.7.4" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Fluens.Web.Messaging.Dashboard" Version="0.7.4" />
                    
Directory.Packages.props
<PackageReference Include="Fluens.Web.Messaging.Dashboard" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Fluens.Web.Messaging.Dashboard --version 0.7.4
                    
#r "nuget: Fluens.Web.Messaging.Dashboard, 0.7.4"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Fluens.Web.Messaging.Dashboard@0.7.4
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Fluens.Web.Messaging.Dashboard&version=0.7.4
                    
Install as a Cake Addin
#tool nuget:?package=Fluens.Web.Messaging.Dashboard&version=0.7.4
                    
Install as a Cake Tool

Fluens.Web.Messaging.Dashboard

Cluster-wide live monitoring surface for the Fluens cross-application messaging mesh. It rolls up the Fluens.Messaging meter instruments (consume.duration / inbox.lag / retry.count / deadletter.count / delivery.latency) from every instance into one cluster aggregate, streams it over Server-Sent-Events to a single static dashboard page, and exposes the per-module dead-letter query + replay surface — all backed by the same Consul the mesh already runs for discovery and durable subscriptions (ADR-0013). There is no second metrics backend. Without Consul the dashboard degrades cleanly to a per-instance view.

How it works

Each instance publishes its own StatsSnapshot roll-up into Consul KV; a blocking-query watch aggregates every live snapshot into a cluster-wide sum (ADR-0013, reusing the ADR-0007 durable-KV + long-poll pattern).

  • StatsSnapshot — an immutable, additive point-in-time roll-up of the Fluens.Messaging meter instruments for one instance (or, once aggregated, the cluster). The two histograms (consume.duration, delivery.latency) keep both a count and a millisecond total so the cluster mean derives as total / count; the counters and the inbox-lag scalar add directly. StatsSnapshot.AggregateCluster(clusterId, instances) is a pure per-metric sum — an empty set yields a zeroed snapshot (the local-only view), never null. It round-trips AOT-safely via the source-generated StatsSnapshotSerializerContext.
  • MeterListenerSnapshotSource (IDisposable, internal) — the instance-local snapshot source: a BCL MeterListener over the Fluens.Messaging meter that accumulates this instance's counters (retry.count, deadletter.count) as running deltas and histograms (consume.duration, delivery.latency) as count + millisecond total. Build() pulls the per-module inbox.lag gauge via RecordObservableInstruments() and sums the per-module measurements into one InboxLag, returning this instance's StatsSnapshot — the real roll-up the publisher writes to KV.
  • StatsPublisher (hosted) — publishes this instance's snapshot to the Consul-KV key fluens/<ClusterId>/messaging/stats/<app>/<instanceId> (<app> = the canonical catalog identity AppInfo.CachePrefix, <instanceId> = AppInfo.CachePrefixUnique). The key is acquired under a Consul session with a TTL (SessionBehavior.Delete), so a dead instance's snapshot auto-evicts from the cluster aggregate when its session lapses — no explicit cleanup path. Each cycle re-acquires the snapshot under the renewed session (drift repair) and renews the session TTL on the same cadence.
  • StatsCatalogWorker (hosted) — a KV blocking-query watch over the cluster stats prefix fluens/<ClusterId>/messaging/stats/. On every index advance — including when a peer's session-TTL-bound key auto-expires — it decodes every per-instance snapshot still present and rebuilds the cluster aggregate via the pure StatsSnapshot.AggregateCluster, atomically swapping it into Current.
  • MessagingDashboardEndpoints (IEndpoint) — maps, under the configured route prefix: the static dashboard.html at the prefix root; a GET /stream Server-Sent-Events (text/event-stream) feed that streams the cluster aggregate (first snapshot immediately on connect, then on the configured interval); and GET /dead-letters over the per-module IMessagingMaintenance surface plus POST /dead-letters/{id}/replay over IMessagingRecovery (ADR-0011 / ADR-0014). Both surfaces are resolved per-request and optional — when an interface is not registered the corresponding endpoint returns an empty / no-op result rather than failing. The page surfaces the SSE connection state with a coloured indicator next to the status text — amber pulsing while connecting, solid green when live, red pulsing while the browser's EventSource is reconnecting.

Local-only graceful degradation

When Discovery is not registered (no IConsulClient in DI) or DiscoveryOptions.ClusterId is blank, both stats workers degrade to local-only: the publisher writes nothing and never starts a session; the worker never watches and Current stays the seeded zeroed (this-instance-only) aggregate. Neither throws and messaging is never blocked. The local-snapshot source is read from the Func<StatsSnapshot> in DI, which delegates to the singleton MeterListenerSnapshotSource roll-up of this instance's Fluens.Messaging meter. The dashboard is non-load-bearing — it is a live operational glance, not a historical metrics store.

Usage

builder.AddFluens()
    .AddWeb()
    .AddMessaging()
    .AddMessagingMesh(ingress => ingress.UseNpgsql(connectionString))
    .AddMessagingDashboard();

var app = builder.Build();
app.MapMessagingMesh();
app.MapMessagingDashboard(); // serves dashboard.html + SSE feed + admin/replay under RoutePrefix

AddMessagingDashboard registers the hosted StatsPublisher + StatsCatalogWorker and the MessagingDashboardEndpoints. The cluster identity is the single-source DiscoveryOptions.ClusterId (the dashboard has no cluster id of its own); register AddDiscovery() so an IConsulClient is present for the cluster-wide view (without it the dashboard runs local-only). When MessagingDashboardOptions.Enabled is false, AddMessagingDashboard is a no-op (registers nothing) and MapMessagingDashboard maps no routes — mirroring the MapFluensHealthchecks "maps nothing when absent" convention.

Configuration

MessagingDashboardOptions is bound from the "Fluens:Web:Messaging:Dashboard" configuration section:

Property Default Description
Enabled true Master flag; when false the dashboard registers nothing and maps no routes.
StreamIntervalSeconds 5 Cadence at which the SSE feed pushes the current cluster aggregate (first snapshot is immediate).
RoutePrefix /messaging/dashboard Base route the static page, SSE feed, and admin/replay endpoints are mapped under.

The Consul-KV publish / session-renew cadence (PublishIntervalSeconds, default 10) and the Consul session TTL (SessionTtlSeconds, default 30 — how long after its last renew a dead instance's key auto-expires) are read directly from the same "Fluens:Web:Messaging:Dashboard" section. The cluster id is single-source in Fluens:Web:Discovery (DiscoveryOptions.ClusterId) — it is the stats key namespace and is not a dashboard option.

This package does not declare a Microsoft.AspNetCore.App framework reference — it inherits ASP.NET Core transitively via Fluens.Web.

Product 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.7.4 41 6/18/2026
0.7.2 46 6/18/2026
0.7.1 47 6/18/2026