Silences¶
Silences are time-bounded label-pattern mutes that suppress dispatched actions during a maintenance window or incident response. They are the primary tool for on-call operators who need to temporarily stop paging without modifying the rule set.
Silences are evaluated after rule evaluation but before provider dispatch, so the audit trail captures which rule verdict would have applied. Operators get full forensic context when debugging silenced alerts, and silences do not interfere with rule coverage analysis.
When to use silences¶
- Maintenance windows — mute alerts for a service you're about to restart, deploy, or take offline.
- Known upstream incidents — suppress the downstream cascade while the root cause is being fixed.
- Noisy alerts under active investigation — stop paging while an engineer is already looking at the issue.
- Incident response — reduce notification storms during a live incident.
Silences are explicitly not a substitute for rules. A rule that blocks actions is a policy; a silence is a temporary operator override. Always expire silences as soon as the reason for them is resolved — Acteon does this automatically at ends_at.
The silence model¶
A silence has five parts:
| Field | Meaning |
|---|---|
matchers | One or more label matchers, combined with AND — all must match |
starts_at | When the silence becomes active (defaults to now) |
ends_at | When the silence expires |
comment | Human-readable reason (required — document why) |
created_by | Caller identity, captured from the API key used |
Matchers¶
Each matcher targets a single label on the dispatched action's metadata.labels map:
| Operator | CLI form | Meaning |
|---|---|---|
equal | name=value | Label value exactly equals the given value |
not_equal | name!=value | Label is missing or has a different value |
regex | name=~pattern | Label value matches the (anchored) regex |
not_regex | name!~pattern | Label is missing or does not match the regex |
Regex patterns are anchored at both ends — a pattern warn.* matches warning but not prewarning. To match a substring, use .*warn.* explicitly.
Regex complexity cap¶
Regex matchers are capped to prevent ReDoS:
- Maximum pattern length: 256 characters
- Maximum compiled DFA size: 64 KB
- Backtracking features (lookaround, backreferences) are not supported because Acteon uses the
regexcrate
Patterns exceeding these limits are rejected with 400 Bad Request at silence creation time. You can never create a silence that could stall the dispatch path.
Tenant scoping and hierarchy¶
Silences are created under a specific (namespace, tenant) and are enforced against the caller's API key grants. A caller scoped to tenant acme can create silences in acme and in any hierarchical child like acme.us-east or acme.us-east.prod. A caller scoped to acme.us-east cannot create silences in acme or acme.eu-west.
The permission required is SilencesManage, held by admin and operator roles but not by viewer. This is deliberately separate from RulesManage — on-call operators need to silence alerts without being able to modify the rule set.
API endpoints¶
| Method | Path | Description |
|---|---|---|
POST | /v1/silences | Create a silence |
GET | /v1/silences | List silences (tenant filter auto-injected for scoped callers) |
GET | /v1/silences/{id} | Get a silence by ID |
PUT | /v1/silences/{id} | Extend ends_at or edit comment (matchers are immutable) |
DELETE | /v1/silences/{id} | Expire a silence immediately |
Create request shape¶
{
"namespace": "prod",
"tenant": "acme",
"matchers": [
{ "name": "severity", "value": "warning", "op": "equal" },
{ "name": "service", "value": "api|worker", "op": "regex" }
],
"duration_seconds": 7200,
"comment": "deploying api v2.3.0 to acme.us-east"
}
You can supply either duration_seconds (convenience) or an explicit ends_at RFC 3339 timestamp. starts_at defaults to now. At least one matcher is required — an empty matcher list is rejected.
List query parameters¶
| Parameter | Default | Description |
|---|---|---|
namespace | (none) | Filter by namespace |
tenant | (auto-injected for single-tenant callers) | Filter by tenant |
include_expired | false | Include silences whose ends_at is in the past |
CLI¶
# Create a 2-hour silence
acteon silences create \
--namespace prod --tenant acme \
--matcher severity=warning \
--matcher team=platform \
--hours 2 \
--comment "canary deploy"
# Create with an explicit end time
acteon silences create \
--namespace prod --tenant acme \
--matcher alertname=HighLatency \
--ends-at 2026-04-11T00:00:00Z \
--comment "investigating upstream"
# List active silences
acteon silences list --namespace prod
# Include expired silences
acteon silences list --include-expired
# Get a specific silence
acteon silences get <id>
# Extend a silence
acteon silences update <id> --ends-at 2026-04-11T06:00:00Z --comment "extended"
# Expire immediately
acteon silences expire <id>
CLI matcher syntax¶
The CLI accepts matchers in a compact key<op>value form:
| CLI form | Operator |
|---|---|
severity=warning | Equal |
severity!=info | NotEqual |
severity=~warn.* | Regex |
severity!~debug|trace | NotRegex |
The longer operators (!~, =~, !=) are matched before = to avoid ambiguity. Use single quotes around regex patterns to protect them from shell expansion.
Text output¶
Silences count=3
state=ACTIVE id=01932c4a-... namespace=prod tenant=acme ends_at=2026-04-11T00:00:00+00:00 matchers=severity="warning", team="platform" comment="canary deploy"
state=ACTIVE id=01932c4b-... namespace=prod tenant=acme ends_at=2026-04-10T12:00:00+00:00 matchers=alertname="HighLatency" comment="investigating upstream"
state=EXPIRED id=01932c49-... namespace=prod tenant=acme ends_at=2026-04-10T06:00:00+00:00 matchers=severity="critical" comment="db migration"
What happens when a silence matches¶
When a dispatched action matches an active silence, Acteon:
- Skips the verdict's provider execution — no email, no page, no webhook call
- Still evaluates all rules — the rule verdict is computed and recorded in the audit trail
- Emits
ActionOutcome::Silenced { silence_id, matched_rule }— which shows up in the audit trail andquery_auditresults - Publishes a stream event — so subscribers see the silenced dispatch in real time with outcome category
silenced
The original action stays in the audit trail with its full payload, matched rule, and silence ID. You can query it later with:
Interaction with other features¶
| Feature | How silences interact |
|---|---|
| Rules | Rules still evaluate; silences just prevent delivery |
| Rule Coverage | Silenced actions count toward coverage (the rule still matched) |
| Audit Trail | Silenced dispatches are fully recorded with the matched silence ID |
| Event Streaming | Silenced dispatches emit a stream event with outcome silenced |
| API Key Scoping | SilencesManage permission + tenant/namespace grants enforce who can mute what |
| Analytics | Silenced dispatches are visible in outcome breakdowns |
Design notes¶
- Expiry is eager at dispatch time — silences whose
ends_athas passed do not match new dispatches, even if the in-memory cache still holds them. This makes the system self-correcting. - DELETE is a soft-expire, not a hard delete —
DELETE /v1/silences/{id}setsends_at = nowand persists the updated record. The silence record itself is preserved so that audit trail references to itssilence_id(recorded on previously silenced dispatches) remain resolvable viaGET /v1/silences/{id}andGET /v1/silences?include_expired=true. A background reaper (Phase 1.5) will eventually purge tombstoned records. - Empty matcher lists are rejected — guards against accidentally muting everything with a bare silence.
- Hierarchical matching is one-way — a silence on
acmecoversacme.us-eastbut NOT vice versa. Sibling tenants (acme.us-eastvs.acme.eu-west) do not cover each other. Dot-strict:acmedoes NOT matchacme-corp. - Matchers are immutable on update — to change matchers, expire the silence and create a new one. This prevents race conditions where an active silence changes shape mid-window.
HA / distributed deployments¶
Silences are eventually consistent across gateway instances. When an operator creates a silence via one instance, the change is visible on that instance immediately and propagates to peer instances via a background sync task that rebuilds the cache from the state store.
| Setting | Default | Description |
|---|---|---|
background.enable_silence_sync | true | Enable periodic silence cache refresh from the state store |
background.silence_sync_interval_seconds | 10 | How often to refresh |
For production HA deployments, leave enable_silence_sync enabled. The 10-second sync interval is the upper bound on how long a silence created on instance A will take to start muting dispatches on instance B. Disabling sync is only appropriate for single-instance deployments.
Simulation example¶
A full end-to-end demo that walks through five silence scenarios — basic matching, multi-matcher AND semantics, regex matchers, hierarchical tenant coverage, and the expire-and-resume lifecycle — is in crates/simulation/examples/silence_simulation.rs:
The simulation uses the harness' recording provider, so it runs offline with no real credentials.