CritterWatch.Services Overview
CritterWatch.Services (NuGet package: CritterWatch) is the server-side library that runs the monitoring console. It contains the Wolverine message handlers, Marten event sourcing projections, SignalR hub, HTTP API, and the embedded Vue SPA.
Package Contents
Hosting Extensions
AddCritterWatch(...)— registers all CritterWatch services into the DI containerUseCritterWatch(...)— maps HTTP endpoints, SignalR hub, and SPA middleware
Marten Event Store
CritterWatch uses Marten to store all service state as events. The event store schema is created automatically in the critterwatch Marten schema:
- Event streams — one per monitored service, keyed by service name
- Projections —
ServiceSummaryProjectionmaterializes aServiceSummarysnapshot document - Timeline projection —
TimelineProjectionproduces an ordered feed of all events - Alert snapshots —
AlertRecorddocuments track alert state
Message Handlers
All ServiceUpdates packets from monitored services are handled by Wolverine message handlers that append domain events to Marten:
ServiceUpdates → WolverineChange events → ServiceSummary projection
AgentHealthReport → AgentHealthState document → AlertRaised/Elevated/Resolved
MessageStoreDiscovered → MessageStoreDiscoveredEvent → ServiceSummarySignalR Relay
A RelayToWebSocketMessageHandler pattern relays all changes from the Wolverine handler pipeline to connected browser clients via SignalR. This creates a real-time feed:
ServiceUpdates received → Marten updated → SignalR message sent → Browser updatesHTTP API
All read queries and command dispatches are exposed as Wolverine.HTTP endpoints under /api/critterwatch/*.
Embedded Vue SPA
The compiled Vue 3 application is embedded as assembly resources when built with -p:EmbedFrontend=true. The UseCritterWatch() middleware serves static files and provides a client-side routing fallback.
Backend Architecture
Thread Safety and Ordering
All ServiceUpdates messages from a given service are processed sequentially (the queue is configured with .Sequential()). This preserves event ordering within a service's stream.
Messages from different services are processed concurrently — each service's queue is independent.
