Skip to content

Web UI Overview

Horsies includes an optional browser dashboard. Enable the web Cargo feature to serve it with axum.

The dashboard reads live state and retained task history. It does not move terminal rows back into the live table. It does not change retention rules.

Terminal window
cargo add horsies --features web

The transport-free horsies::monitoring module is always available. The horsies::web router and embedded dashboard require the web feature.

The task view merges two sources:

  • horsies_tasks supplies PENDING, CLAIMED, and RUNNING tasks.
  • horsies_task_history supplies retained terminal tasks.

The default history window is the last 24 hours. The maximum accepted window is 30 days. Horsies refuses larger windows instead of reducing them.

The task view supports status, queue, task name, worker, and error filters. It also supports search and ordered pages. Null sort values appear last in both sort directions.

The total for an unfiltered task list can use a planner estimate. Filtered totals are exact. Facet counts sum live and retained rows before ranking the groups.

Task detail verifies the retained history digest before decoding the result or attempt snapshot. A corrupt retained row returns an error. It is never shown as a valid task.

The workflow list shows current workflow state and progress. The detail view shows the node graph, node status, task links, and stored errors.

Workflow state includes EXPIRED. A paused workflow can expire when paused_workflow_auto_cancel_after is configured.

The worker view shows worker state and recent activity. The schedule view shows the persisted scheduler state.

Worker and workflow reads use the current operational tables. Task aggregates combine live tasks with the selected retained-history window.

The dashboard performs an initial fetch for each view. It then listens for server-sent invalidation events.

The server listens to the task-status, workflow-status, and worker-state PostgreSQL channels. It debounces events for 250 milliseconds. One event can carry at most 100 IDs. An overflow emits the same topic with an empty ID list. The empty list causes a broader refetch.

The event listener owns one dedicated PostgreSQL session. It is separate from task-result listeners.

A listener failure emits the degraded topic and closes the stream. The browser then falls back to polling while it reconnects.

Terminal task moves emit task_done. The dashboard does not subscribe to that channel. It converges on a later subscribed event or client refetch.

The dashboard exposes four actions when the deployment enables them:

ResourceAction
TaskCancel
WorkflowPause
WorkflowResume
WorkflowCancel

Task retry is not a dashboard action. Retained tasks can be rerun through the Rust API. A rerun creates a new task with lineage to the source task.

Every action requires authorization and X-Horsies-Intent: action. Every action also requires an exact schema match. Reads can remain available when the schema version does not match.

See Action Semantics for state rules and response codes.

BoundRule
Default history window24 hours
Maximum history window30 days
Task list limit1 through 200
Workflow list limit1 through 200
Task page reachoffset + limit <= 500
Worker history limit1 through 1000

Time bounds accept timezone-aware ISO-8601 timestamps. The server normalizes them to UTC. since must be earlier than until.

The web server probes schema state without running migrations or cutover DDL. The result is cached for 60 seconds.

StateReadsActions
MATCHAvailableCan be enabled
MISMATCHAvailable where the stored schema can answer the queryDisabled
CUTOVER_REQUIREDAvailable where the stored schema can answer the queryDisabled
ABSENTDashboard shell onlyDisabled
UNKNOWNDashboard shell onlyDisabled

SCHEMA_INCOMPATIBLE reports a mismatch, missing schema, or incomplete cutover. SCHEMA_UNKNOWN reports a failed schema probe with no cached result.

Use horsies web for a standalone server. Mount create_monitoring_router in an existing axum service when the host must own authentication or task registration.

See Deployment and Authentication for both forms.