AlertRuleService¶
Target
This page describes intended behaviour or structure. No implementation is claimed unless a section is explicitly marked Current implementation or Evidence.
| Bounded context | BC-21 Operations |
| Platform / plane | Observability / Trust & Operations |
| Deployment granularity | module of host · host ObservabilityHost |
| Status | target · ConnectSoft.Factory.Observability.Alerts |
| Built from | connectsoft-microservice · libraries: connectsoft-extensions-saas-abstractions, connectsoft-extensions-messaging-model, connectsoft-extensions-persistence-model-nhibernate, connectsoft-extensions-scheduler-model-hang-fire |
| Decisions | ADR-0018 |
| Traceability | FR-10 FUX-04 NFR-10 NFR-17 XL-06 XL-16 |
Purpose and responsibilities¶
AlertRuleService is the one place an operator is told something needs them. Rules fire from events (an SLO breach, a host turning Unhealthy, a tool effect settling as Uncertain, a High or Critical audit finding, a failed delivery) or from metric conditions evaluated every minute against the backend; instances are deduplicated by a key template, carry a severity, are acknowledged and resolved (automatically on the source's recovery event, or manually with a reason) and are delivered through the Studio notification service and, for tenants that want them, chat and email connectors of the Integration platform.
Platform rules — health, chain validity, uncertain effects — are always on and cannot be removed per tenant; tenants add their own.
Context and boundaries¶
flowchart LR
S["AlertRuleService"]
StudioBff["StudioBff"] -->|sync-http| S
S -->|grpc| ConnectorRegistryService["ConnectorRegistryService"]
S -->|event| StudioNotificationService["StudioNotificationService"]
S -->|sync-http| ext_otel_backend["ext-otel-backend"]
S -. "AlertRuleChanged" .-> E_AlertRuleChanged(("event"))
S -. "AlertFired" .-> E_AlertFired(("event"))
S -. "AlertResolved" .-> E_AlertResolved(("event"))
External delivery is never a raw webhook from this service: it goes through ConnectorRegistryService with the external action class and the tenant's own connection, so the same policy and receipts apply as to any other external call. Incidents (opening, paging, post-mortems) are a later service; until then an alert is the unit of operator attention.
Domain model¶
AlertRule — A rule with a source condition, severity, deduplication key template, routing targets and suppression windows. (catalog entry)
| Field | Type | Required | Description |
|---|---|---|---|
ruleId |
guid |
yes | |
tenantId |
string |
yes | |
name |
string |
yes | |
sourceKind |
enum:AlertSourceKind |
yes | |
condition |
json |
yes | Event filter or metric threshold with duration |
severity |
enum:AlertSeverity |
yes | |
dedupKeyTemplate |
string |
yes | |
routes |
json |
yes | studio-notification |
suppression |
json |
no | |
active |
bool |
yes |
Invariants:
- Platform rules (health, chain validity, uncertain effects) are always active and cannot be deleted per tenant; tenants add their own.
- Routes to external channels go through connectors (BC-17) with the external class and the tenant's connection; never raw webhooks.
Events: AlertRuleChanged · Tables: AlertRules · Repository: AlertRuleRepository
AlertInstance — One fired alert with its deduplication key, severity, source reference, acknowledgement and resolution. (catalog entry)
| Field | Type | Required | Description |
|---|---|---|---|
alertId |
guid |
yes | |
tenantId |
string |
yes | |
ruleId |
guid |
yes | |
dedupKey |
string |
yes | |
severity |
enum:AlertSeverity |
yes | |
sourceRef |
string |
yes | SLO id, host id, invocation id, finding id or metric query. |
state |
enum:AlertState |
yes | |
firedAt |
datetime |
yes | |
acknowledgedBy |
string |
no | |
resolvedAt |
datetime |
no | |
notifications |
json |
yes | Deliveries made per route with receipts. |
Invariants:
- The same dedupKey while an instance is Fired or Acknowledged does not fire again; it increments the occurrence count.
- Resolution is automatic on the source's recovery event or manual with a reason.
stateDiagram-v2
Fired --> Acknowledged : Acknowledge
Fired --> Resolved : SourceRecovered
Acknowledged --> Resolved : SourceRecoveredOrManual
Fired --> Suppressed : SuppressionWindow
Events: AlertFired, AlertResolved · Tables: AlertInstances · Repository: AlertInstanceRepository
erDiagram
AlertRule {
guid ruleId PK
string tenantId
string name
enum_AlertSourceKind sourceKind
json condition
enum_AlertSeverity severity
string dedupKeyTemplate
json routes
json suppression
bool active
}
AlertInstance {
guid alertId PK
string tenantId
guid ruleId
string dedupKey
enum_AlertSeverity severity
string sourceRef
enum_AlertState state
datetime firedAt
string acknowledgedBy
datetime resolvedAt
json notifications
}
Entities and value objects¶
None modelled
No entities or value objects are modelled for this item yet.
Data model and storage¶
| Store | Role | Engine / profile | Tables |
|---|---|---|---|
| Operations projection store | primary | azure-sql / nhibernate-sqlserver | AlertRules, AlertInstances |
| Table | Owner | Columns | Indexes |
|---|---|---|---|
dbo.AlertRules |
AlertRule | 10 | 1 |
dbo.AlertInstances |
AlertInstance | 11 | 2 |
Full DDL: appendix.
APIs¶
| Method | Path | Operation | Scope | Side effects | Idempotency | Gateway | Summary |
|---|---|---|---|---|---|---|---|
GET |
/factory/alerts |
ListAlerts | factory.operations.read |
read | natural | GW-03 | Alert instances by state and severity with sources and notifications. |
POST |
/factory/alerts/{alertId}/acknowledge |
AcknowledgeAlert | factory.operations.operate |
shared-write | natural | GW-03 | Acknowledge an alert (Operator). |
POST |
/factory/alerts/{alertId}/resolve |
ResolveAlert | factory.operations.operate |
shared-write | natural | GW-03 | Resolve manually with a reason. |
GET |
/factory/alert-rules |
ListAlertRules | factory.operations.read |
read | natural | GW-03 | Rules in scope. |
PUT |
/factory/alert-rules/{name} |
SetAlertRule | factory.operations.admin |
shared-write | natural | GW-03 | Create or change a tenant rule with routes through connectors. |
None modelled
No gRPC methods are modelled for this item yet.
Messages¶
| Event | Topic | Scope / v | Aggregate | Consumers | Summary |
|---|---|---|---|---|---|
| AlertRuleChanged | operations.alerts.v1.alert-rule-changed |
integration / 1 | AlertRule | StudioBff, AuditService | A rule was created, changed or deactivated. |
| AlertFired | operations.alerts.v1.alert-fired |
integration / 1 | AlertInstance | StudioRealtimeGateway, FleetIncidentService, StudioBff, StudioNotificationService, DashboardService | An alert fired (or re-occurred). |
| AlertResolved | operations.alerts.v1.alert-resolved |
integration / 1 | AlertInstance | StudioRealtimeGateway, StudioBff, DashboardService | An alert was resolved. |
AlertRuleChanged payload:
| Field | Type | Required | Description |
|---|---|---|---|
ruleId |
guid |
yes | |
tenantId |
string |
yes | |
name |
string |
yes | |
active |
bool |
yes |
AlertFired payload:
| Field | Type | Required | Description |
|---|---|---|---|
alertId |
guid |
yes | |
tenantId |
string |
yes | |
ruleId |
guid |
yes | |
severity |
enum:AlertSeverity |
yes | |
sourceRef |
string |
yes | |
dedupKey |
string |
yes |
AlertResolved payload:
| Field | Type | Required | Description |
|---|---|---|---|
alertId |
guid |
yes | |
tenantId |
string |
yes | |
resolvedBy |
string |
no |
| Command | Handled by | Result events | Summary |
|---|---|---|---|
AcknowledgeAlert |
AlertInstance | — | |
ResolveAlert |
AlertInstance | AlertResolved | |
SetAlertRule |
AlertRule | AlertRuleChanged |
| Event | Producer | Handler | Purpose |
|---|---|---|---|
| SloBreached | SloService | FireFromSlo |
Breaches and fast burns. |
| SloRecovered | SloService | ResolveFromSlo |
Auto-resolve. |
| ServiceHealthChanged | SloService | FireFromHealth |
Host health degradations. |
| ToolEffectUncertain | ToolAdapterService | FireFromUncertain |
Uncertain effects need an operator. |
| FindingRaised | AuditService | FireFromFinding |
High and Critical findings. |
| DeliveryFailed | ConnectorRegistryService | FireFromDelivery |
Failed deliveries. |
Workers and jobs¶
| Worker | Trigger | Output events | Retry | Idempotency key | Summary |
|---|---|---|---|---|---|
| MetricRuleEvaluator | schedule */1 * * * * |
AlertFired, AlertResolved | fixed | ruleId + minute |
Evaluates metric-threshold rules against the backend on a schedule and fires or resolves instances. |
| Notifier | event | — | exponential | alertId + route |
Delivers notifications for fired alerts through the Studio and connectors with receipts. |
Actors and grains¶
None modelled
No grains are modelled for this item yet.
Sagas and long-running flows¶
None modelled
No sagas are modelled for this item yet.
sequenceDiagram
participant S as SloService
participant T as ToolAdapterService
participant A as AlertRuleService
participant N as StudioNotificationService
participant C as ConnectorRegistryService
S-)A: SloBreached
T-)A: ToolEffectUncertain
A->>A: match rules, compute dedup key, open or increment instance
A-)N: AlertFired → Studio notification
A->>C: deliver via chat / email connector (external class, receipts)
S-)A: SloRecovered
A->>A: resolve instance → AlertResolved
Options and configuration¶
| Section | Key | Type | Default | Reloadable | Secret | Summary |
|---|---|---|---|---|---|---|
Observability:Alerts |
DefaultSuppressionMinutes |
int | 10 |
yes | no | Suppression after resolution before the same key can fire again. |
Metrics and observability¶
| Metric | Instrument | Unit | Dimensions | Summary |
|---|---|---|---|---|
connectsoft.factory.alerts.fired |
counter | {alert} | tenant, sourceKind, severity | Alerts fired. |
connectsoft.factory.alerts.open |
updown | {alert} | tenant, severity | Open alerts. |
connectsoft.factory.alerts.time_to_acknowledge |
histogram | s | tenant, severity | Time to acknowledgement. |
Security¶
| Authentication | client-credentials |
| Scopes | factory.operations.read (Read alerts and rules.); factory.operations.operate (Acknowledge and resolve (Operator).); factory.operations.admin (Rules (Platform admin, Workspace admin).) |
| Roles | Operator, WorkspaceAdmin, PlatformAdmin, Observer |
| Tenant isolation | row-filter |
| Data classification | internal |
| Max side-effect class | shared-write |
| Secrets | — |
Dependencies¶
Outbound
| Target | Kind | Purpose | Failure mode | Required |
|---|---|---|---|---|
| ConnectorRegistryService | grpc | Chat and email deliveries through connectors. | degrade | no |
| StudioNotificationService | event | Studio notifications. | queue | yes |
| ext-otel-backend | sync-http | Metric rule evaluation. | degrade | yes |
Inbound
| Target | Kind | Purpose | Failure mode | Required |
|---|---|---|---|---|
| StudioBff | sync-http | Alert and rule views, acknowledgement. | — | yes |
Failure and recovery¶
| Scenario | Detection | Recovery | Data impact | RTO (min) |
|---|---|---|---|---|
| Notification channel down | delivery failures | retries; the Studio notification is always delivered; receipts record failures | delayed external notification | 30 |
NFR targets¶
| Target | Class value (pilot-projection) | Override |
|---|---|---|
| latency_p95_ms | 500 | — |
| availability_pct | 99.5 | — |
| throughput_rps | 100 | — |
| rpo_minutes | 15 | — |
| rto_minutes | 240 | — |
| cost_class | low | — |
Deployment¶
| Granularity | module of host · host ObservabilityHost |
| Topologies | saas-default, hybrid, on-prem, hybrid-compute |
| Runtime | —; replicas —–— |
| Ports | — |
Current implementation¶
Nothing: the estate has no alerting of its own beyond what the Azure Monitor backend offers per installation.
Later capabilities¶
IncidentService (incident lifecycle, paging schedules, post-mortems linked to runs); alert correlation across generated products in the fleet; agent-proposed alert rules from recurring patterns.
Decisions and traceability¶
| Family | Ids |
|---|---|
| FR | FR-10 |
| FUX | FUX-04 |
| NFR | NFR-10, NFR-17 |
| XL | XL-06, XL-16 |