Skip to main content

Operations metrics

Workflow operations data — approval backlog, run volume, failures, and lead time — is exposed for third-party dashboards in two shapes, both scoped to the caller's tenant and, apart from the failure list noted below, both available to any authenticated user.

Runs an access-control tag hides from the caller are left out of every view below, exactly as they are absent from the run list itself, so a metric never names a run its reader could not open.

Runs started from a still-draft workflow (a developer/super_admin pre-publish test run) are recorded with isDraft: true and excluded from every metric below — both the Prometheus KPIs and the aggregate sub-resources, including the approval-backlog views — so throwaway test data never skews the numbers. The flag is fixed when the run starts; publishing the workflow afterwards does not reclassify runs that already happened.

Prometheus endpoint​

GET /api/v1/metrics renders the single-value KPIs in Prometheus text exposition format. Every sample carries a tenant label.

Approvals:

MetricMeaning
a2flow_approvals_pendingApproval requests awaiting a decision
a2flow_approvals_pending_over_threshold{threshold}Of those, the ones waiting longer than the threshold (default 24h)
a2flow_approval_pending_age_seconds_maxHow long the longest-waiting request has been waiting
a2flow_approvals_decided_today{decision}Approvals decided today, by approved / rejected / returned

Workflow executions:

MetricMeaning
a2flow_workflow_executions_activeRuns currently in progress (running or scheduled)
a2flow_workflow_executions_finished_today{status}Runs that finished today, by terminal status
a2flow_workflow_executions_started_recently{window,workflow}Runs started in the last 24h, by workflow
a2flow_workflow_executions_failed_recently{window}Runs that finished in failure in the last 24h
a2flow_workflow_tasks_failed_recently{window,error_kind}Tasks that failed in the last 24h, by cause
a2flow_workflow_execution_lead_time_seconds_avg{window,workflow}Mean start-to-finish duration of runs finishing in the last 24h

Notification email:

MetricMeaning
a2flow_email_queue_depth{status}Emails in the outgoing queue, by pending / sending / sent / failed
a2flow_email_queue_oldest_pending_age_secondsHow long the longest-waiting undelivered email has waited — rises when the relay is unreachable

?thresholdHours= overrides the stalled-approval cutoff. TIMEZONE (an IANA name, default UTC; see Server settings) decides where "today" starts; an unrecognized name falls back to UTC rather than failing startup.

The endpoint is protected by the ordinary session cookie, so a scrape config has to carry one. GET is a safe method, so no CSRF token is needed:

- job_name: a2flow
metrics_path: /api/v1/metrics
http_headers:
Cookie: { values: ["a2flow_session=<token>"] }

The session's idle timeout slides on every request, so a running scrape keeps its own session alive indefinitely; it does not survive a backend restart or an explicit logout, which is when the token has to be refreshed. A scrape covers exactly one tenant — to watch several, configure one job per tenant.

Aggregate sub-resources​

Anything whose natural key is a user id, a run id, or a free-text error message is deliberately kept out of Prometheus — those are unbounded label sets. Those views are served as JSON sub-resources of the existing collections instead, in the usual {meta, data, error} envelope:

EndpointReturns
GET /api/v1/workflow-executions/by-workflowPer-workflow run counts (total / running / completed / failed; running includes scheduled runs) and average lead time
GET /api/v1/workflow-executions/lead-time-trendDaily average lead time, one bucket per calendar day including empty ones
GET /api/v1/workflow-executions/failuresRuns needing triage, each with its failed tasks and their recorded cause. admin only, since it quotes task titles and error messages from runs the caller may not be part of
GET /api/v1/approvals/by-approverPending-approval backlog per designated approver
GET /api/v1/approvals/by-workflowThe same backlog, grouped by workflow

The execution endpoints take since / until (ISO-8601, defaulting to the last 30 days, capped at 366) and limit; the approval endpoints take thresholdHours (default 24) and limit. Backlog entries come back longest-single-wait first, so ?limit=5 is the worst five. Durations are always whole seconds.

by-approver groups by an approval's destination, which may be a user or a group. Each entry carries a groupKind of "user" or "group" to tell them apart: a "user" entry gives the id only, while a "group" entry also carries the group's name in groupLabel.

A task that fails records why: error_kind (one of api_error, timeout, script_error, invalid_input, permission_denied, rejected, other) and a free-text error_message are stored alongside status="failed". Both are ordinary task fields, so a task list can be filtered on them — e.g. ?q=errorKind:eq:timeout.