{% extends 'clean_base.axml' %} {% set modal_name = 'Dashboard' %} {% macro dashctrl() %} { window: 'all', metrics: { published: 0, delivered: 0, retrying: 0, pending: 0, failed: 0, total: 0, success_rate: null }, failures: [], subs: [], loading: false, busy: null, showBackfill: false, backfillSub: null, backfillSubName: '', backfillSince: '', backfillCount: null, backfillRunning: false, init(){ this.refresh(); }, refresh(){ this.loadMetrics(); this.loadFailures(); this.loadSubs(); }, loadMetrics(){ fetch(`/v1/metrics/deliveries?window=${this.window}`, { credentials: 'include' }) .then(r => r.json()) .then(data => { this.metrics = data; }) .catch(() => ShowFeedback('error', 'Failed to load metrics')); }, loadFailures(){ this.loading = true; fetch('/v1/gists?status=failed&pagination=50', { credentials: 'include' }) .then(r => r.json()) .then(data => { this.failures = data.data || []; this.loading = false; }) .catch(() => { this.loading = false; }); }, loadSubs(){ fetch('/v1/metrics/subscriptions', { credentials: 'include' }) .then(r => r.json()) .then(data => { this.subs = data.data || []; }) .catch(() => {}); }, setWindow(w){ this.window = w; this.loadMetrics(); }, fmtRate(){ return this.metrics.success_rate === null ? '—' : `${this.metrics.success_rate}%`; }, replayOne(id){ this.busy = id; fetch(`/v1/regists/${id}`, { method: 'POST', credentials: 'include' }) .then(async r => { if(!r.ok) throw await r.json().catch(() => ({})); return r.json(); }) .then(data => { if(data.delivered) ShowFeedback('success', `Gist ${id} replayed — delivered (${data.status_code})`); else ShowFeedback('warning', `Gist ${id} replayed but still failing${data.status_code ? ' ('+data.status_code+')' : ''}`); this.refresh(); }) .catch(err => ShowFeedback('error', err?.error || 'Replay failed')) .finally(() => { this.busy = null; }); }, requeueOne(id){ this.busy = id; fetch(`/v1/requeues?gist=${id}`, { method: 'POST', credentials: 'include' }) .then(async r => { if(!r.ok) throw await r.json().catch(() => ({})); return r.json(); }) .then(data => { ShowFeedback('success', `Gist ${id} requeued — daemon will retry it`); this.refresh(); }) .catch(err => ShowFeedback('error', err?.error || 'Requeue failed')) .finally(() => { this.busy = null; }); }, openBackfill(sub){ this.backfillSub = sub.subscription; this.backfillSubName = `${sub.subscriber} · ${sub.action}`; this.backfillSince = ''; this.backfillCount = null; this.showBackfill = true; this.dryBackfill(); }, dryBackfill(){ fetch('/v1/backfills', { method: 'POST', credentials: 'include', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ subscription: this.backfillSub, since: this.backfillSince, dry_run: true }) }).then(r => r.json()).then(data => { this.backfillCount = data.count; }) .catch(() => ShowFeedback('error', 'Could not compute backfill count')); }, runBackfill(){ this.backfillRunning = true; fetch('/v1/backfills', { method: 'POST', credentials: 'include', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ subscription: this.backfillSub, since: this.backfillSince }) }).then(r => r.json()).then(data => { this.backfillRunning = false; this.showBackfill = false; ShowFeedback('success', `Backfilling ${data.backfilled} historical events to this subscription`); this.refresh(); }).catch(() => { this.backfillRunning = false; ShowFeedback('error', 'Backfill failed'); }); } } {% endmacro %} {% block easel %}
Published
Delivered
Retrying
Failed
Success rate
Needs attention
Action Publisher → Subscriber Endpoint Attempts Code Last error Last attempt Actions
Subscription health
Subscriber Action Endpoint Delivered Failed Most recent error Backfill
{% endblock %}