Outbound Events
Outbound events are messages your monitored service publishes back to the CritterWatch console. They flow over your existing Wolverine transport from the service to the console's critterwatch queue.
This page is for integrators who want to consume the same telemetry from their own infrastructure (a separate analytics pipeline, a custom dashboard, an audit system, etc.). For day-to-day operation, you don't need any of this — the console handles it for you.
How telemetry is shaped
Most outbound traffic is wrapped in a single ServiceUpdates batch published once per second. A few message types are published on demand in response to specific console queries (handler source code, HTTP chain source code, pending-migration probe results, tenant list refresh).
The batch carries everything CritterWatch needs to render a service's pages in one round-trip — endpoint snapshot, subscription catalog, persistence counts, shard states, agent health, and any change events that occurred since the previous batch.
What's in ServiceUpdates
public record ServiceUpdates(
string ServiceName,
string Label,
string WolverineVersion,
EndpointState[] Endpoints,
MessagingSubscription[] Subscriptions,
WolverineChange[] Changes,
AgentHealthReport[] AgentHealth,
PersistenceCounts PersistenceCounts,
ShardStateSnapshot[] ShardStates
);The Changes array carries the discrete state-change events that occurred since the previous batch. The other arrays are full snapshots — current endpoints, current subscriptions, current health.
Change-event categories
The WolverineChange discriminator covers:
| Category | Trigger | Drives |
|---|---|---|
NodeAdded / NodeRemoved | Process node joined or left the cluster | Cluster tab → Nodes view |
LeadershipChanged | New leader elected | Cluster tab → Leader pill |
AgentStarted / AgentStopped | Agent assignment changes | Cluster tab → Agents view |
EndpointAdded / EndpointStopped | Listener or sender lifecycle | Endpoints tab |
CircuitBreakerTripped / CircuitBreakerReset | Endpoint resilience event | Endpoints tab + alert |
BackPressureTriggered / BackPressureLifted | Flow-control event | Endpoints tab + alert |
ExceptionTriggered | Handler exception | Timeline + DLQ rate metrics |
On-demand response messages
These are published in response to a specific console query rather than on the regular cadence:
| Response | Triggered by | Carries |
|---|---|---|
HandlerSourceCodeResponse | RequestHandlerSourceCode | Generated handler source code for a message type |
HttpChainSourceCodeReported | RequestHttpChainSourceCode | Generated source code for an HTTP chain |
PendingMigrationsReportedResponse | RequestPendingMigrationsCheck | Pending EF Core migration list for a DbContext |
TenantListResponse | RequestTenantList | Current tenant list for multi-tenant services |
AgentHealthReport | RequestAgentHealthReport (or scheduled) | Agent health snapshot |
RestartProjectionResult | RestartProjection / RebuildProjection | Success/failure of the operation |
ScheduledMessageEdited | EditScheduledMessage | Confirmation of edit + new execution time |
StaleNodesEjected | EjectNode | Confirmation of ejected node ids |
SubscriptionOrProjectionRestarted | Auto-restart on stall | Why and when |
Capability advertisement (on startup)
The first ServiceUpdates batch after startup carries the full capability set:
MessagingSubscription[]— every message type with its handler binding and routing role (Handler / Publisher).EndpointState[]— every listener and sender with full configuration.MessageStoreDiscovered— every Wolverine durability store with its database URI and store type (Postgresql/SqlServer/InMemory).- Event-store metadata (Marten / Polecat).
- Tenancy mode + current tenant list.
- Wolverine version string.
This snapshot is re-issued whenever the Wolverine runtime is reinitialized. It replaces the prior shape wholesale — no merge logic.
Causation discovery
When the runtime observes that handling message A resulted in publishing message B, the service publishes a MessageCausationDiscovered event. The console aggregates these to draw the causation graph on the Message Topology page.
Causation is reported per discovered pair, not on every occurrence — once a causation is known, repeated observations don't re-publish.
Message shape on the wire
Telemetry uses Wolverine's standard JSON envelope on the transport. When consumed via SignalR (e.g., by the browser), messages use the CloudEvents wrapper:
{
"type": "service_updated",
"data": {
"serviceName": "trip-service",
...
}
}The type discriminator is snake_case derived from the C# type name. Properties inside data are camelCase. Enums serialize as string names.
Consuming telemetry from your own infrastructure
If you want to subscribe to the same telemetry stream from a separate process (analytics, custom audit, etc.):
- Listen on the
critterwatchRabbitMQ queue alongside the console — or have your service fan out to a second queue using Wolverine's transport routing. - Reference
Wolverine.CritterWatchand deserialize the message types directly. - Treat
ServiceUpdatesas a complete snapshot — don't try to reconstruct state from theChangesarray alone, because some change events depend on having seen the prior snapshot.
For analytics pipelines, the high-volume surface is ServiceUpdates (one per second per service). The bursty / on-demand surface is the response messages and the alert lifecycle events emitted by the console (which are republished over SignalR for the browser; you can subscribe to that hub if your consumer is a server-side SignalR client).
