EdgeInteract
Completion Rate
Completion rate is the percentage of published interactions that receive a user response before expiry. It is the primary health indicator for EdgeInteract deployments — a falling completion rate signals delivery failures, user disengagement, or misconfigured timeout windows.
Completion Rate Definition
For a given time window, completion rate is calculated as:
completion_rate = interaction_responses_total / interaction_published_total * 100
The complementary rate — timeout rate — is:
timeout_rate = interaction_timeout_total / interaction_published_total * 100
Blocked interactions (rejected by pre-send hooks) are counted separately in interaction_blocked_total and are excluded from the completion rate denominator, since they were never delivered.
Example Breakdown
87%
Completed (responded)
9%
Timed Out
4%
Blocked (pre-send hooks)
Metrics Involved
| Metric | Type | Counts |
|---|---|---|
interaction_published_total | Counter | Every interaction that passed pre-send hooks and was delivered to the pipeline |
interaction_responses_total | Counter | Every interaction that received a user response (any outcome) |
interaction_timeout_total | Counter | Every interaction that expired without a response |
interaction_blocked_total | Counter | Interactions rejected before delivery by pre-send hooks |
PromQL Queries for BizFirst Observe
// Completion rate (%) over 1h sliding window — all types
100 * (
sum(increase(interaction_responses_total[1h]))
/
sum(increase(interaction_published_total[1h]))
)
// Timeout rate (%) — approval interactions only
100 * (
sum(increase(interaction_timeout_total{type="approval"}[1h]))
/
sum(increase(interaction_published_total{type="approval"}[1h]))
)
// Blocked rate (%) — segmented by hook name
100 * (
sum by (blocked_by) (increase(interaction_blocked_total[1h]))
/
sum(increase(interaction_published_total[1h]) + increase(interaction_blocked_total[1h]))
)
Alert Thresholds
| Condition | Severity | Default Threshold |
|---|---|---|
| Timeout rate > 5% over 5 minutes | Warning | 5% |
| Timeout rate > 15% over 5 minutes | Critical | 15% |
| Completion rate < 80% over 1 hour | Warning | 80% |
| Blocked rate > 10% over 5 minutes | Warning | 10% |
Querying Completion Rate in Code
// Admin API endpoint — completion rate by type for last 24h
[HttpGet("stats/completion-rate")]
[Authorize(Roles = "admin")]
public async Task<CompletionRateReport> GetCompletionRateAsync(
[FromQuery] string? type,
[FromQuery] int windowHours = 24,
CancellationToken ct = default)
{
var since = DateTime.UtcNow.AddHours(-windowHours);
var query = new AuditQuery { Type = type, CreatedAfter = since };
var all = await _auditStore.CountAsync(query, ct);
var responded = await _auditStore.CountAsync(
query with { Statuses = [InteractionStatus.Responded] }, ct);
var timedOut = await _auditStore.CountAsync(
query with { Statuses = [InteractionStatus.TimedOut] }, ct);
var blocked = await _auditStore.CountAsync(
query with { Statuses = [InteractionStatus.Blocked] }, ct);
return new CompletionRateReport
{
TotalPublished = all,
Responded = responded,
TimedOut = timedOut,
Blocked = blocked,
CompletionRatePct = all > 0 ? (double)responded / all * 100 : 0,
TimeoutRatePct = all > 0 ? (double)timedOut / all * 100 : 0
};
}
Interpreting Low Completion Rates
| Pattern | Likely Cause | Investigation |
|---|---|---|
| Sudden drop in completion rate for all types | Delivery failure (SignalR disconnects, EdgeStream outage) | Check interaction_in_flight — is it growing without responses? |
| Low completion for one specific type | UI rendering issue for that interaction type | Check browser console for render errors; review InteractionContainer renderer map |
| Gradually declining completion rate | User disengagement or notification fatigue | Review volume per user; consider reducing frequency or increasing priority of critical interactions |
| High blocked rate | Rate limit hook is too aggressive | Review RateLimitInteractionHook configuration; check interaction_blocked_total by blocked_by label |
First-to-Respond Interactions
For role-targeted interactions (first-to-respond wins), the interaction is counted as one response in
interaction_responses_total regardless of how many users received it. The interaction_published_total is also counted once per interaction, not once per recipient.