Files
sencho/docs/features/alerts-notifications.mdx
T
Anso 08f57c7141 feat(settings): surface security, notifications, and app store on remote nodes (#716)
Flip Security (Trivy), Notifications (agents + history), and App Store from
global-and-hidden-on-remote to node-scoped so operators can manage them when a
remote node is selected in the node picker. The primary instance proxies the
calls to each remote, which resolves the correct per-instance binary state,
agent config, and template registry.

Backend: key `agents` and `notification_history` by `node_id` with idempotent
column-add migrations and a `(node_id, type)` unique index on agents, matching
the Labels pattern. Thread `req.nodeId` through the /api/agents and
/api/notifications routes. Internal NotificationService and ImageUpdateService
writes resolve the middleware default via `NodeRegistry.getDefaultNodeId()` so
monitor-emitted rows share a bucket with user-facing ones (avoids split-brain
where the UI sees test notifications but not internal alerts).

Frontend: split Security on remote to render only the scanner card and hide
scan policies and CVE suppressions (those remain control-plane-only). Drop the
misleading "Always Local" badge on Developer since retention windows govern
backend jobs, not UI state. Flip the App Store registry to node-scoped.

Docs: add a "What Settings apply per node" table to multi-node, clarify
remote alert setup in alerts-notifications, and note Trivy's per-host install
in vulnerability-scanning.
2026-04-20 21:04:09 -04:00

274 lines
16 KiB
Plaintext

---
title: Alerts & Notifications
description: Set threshold-based alerts on container metrics and route them to Discord, Slack, or any webhook.
---
Sencho can watch your containers for resource anomalies and notify you when thresholds are breached. Alerts are defined per stack, and notifications are delivered through external channels you configure.
## Setting up notification channels
At least one channel must be enabled before alerts can be delivered externally. Go to **Settings > Notifications**.
<Frame>
<img src="/images/alerts-notifications/notifications-settings.png" alt="Notifications & Alerts settings showing Discord, Slack, and Webhook tabs" />
</Frame>
Three channel types are available, each configured with a webhook URL and an enable/disable toggle:
### Discord
1. In Discord, go to your server's **Settings > Integrations > Webhooks**
2. Click **New Webhook**, choose a channel, and copy the webhook URL
3. In Sencho, open **Settings > Notifications > Discord**, paste the URL, enable the toggle, and click **Save**
4. Click **Test** to send a test message and verify the connection
### Slack
1. In Slack, go to **api.slack.com/apps**, create an app, and add the **Incoming Webhooks** feature
2. Activate it and copy the generated webhook URL for your chosen channel
3. In Sencho, open **Settings > Notifications > Slack**, paste the URL, enable the toggle, and click **Save**
### Generic Webhook
Any HTTPS endpoint that accepts a POST with a JSON body can receive Sencho alerts. Go to **Settings > Notifications > Webhook**, enter the URL, enable the toggle, and click **Save**.
<Note>
All webhook URLs (Discord, Slack, and generic) must use HTTPS. HTTP URLs are rejected.
</Note>
The payload format is:
```json
{
"level": "warning",
"message": "cpu_percent exceeded 90% for 5 minutes on stack my-app",
"timestamp": "2026-03-22T10:00:00.000Z"
}
```
## Creating stack alerts
Stack alerts are configured per stack. Right-click a stack in the sidebar (or click the three-dot menu) and select **Alerts**. A panel slides open showing existing rules and a form to create new ones.
<Frame>
<img src="/images/alerts-notifications/alert-panel.png" alt="Stack Alerts panel showing the notification status banner and alert rule form" />
</Frame>
The panel includes:
- **Notification status banner** at the top, showing whether channels are configured. If no channels are enabled, a warning explains that rules will be evaluated but no external notifications will be sent.
- **Existing Rules** section listing all active rules for this stack, each showing the metric, condition, duration, and cooldown. Hover over a rule to reveal the delete button.
- **Add New Rule** form with the fields described below.
### Alert fields
| Field | Description |
|-------|-------------|
| **Metric** | The container metric to watch (see table below) |
| **Operator** | Comparison: Greater than, Greater or equal, Less than, Less or equal, Equals |
| **Threshold** | The numerical value to compare against |
| **Duration (mins)** | How long the condition must hold before firing (default: 5) |
| **Cooldown (mins)** | Minimum time between repeated notifications for this rule (default: 60) |
### Available metrics
| Metric | Description |
|--------|-------------|
| CPU Usage (%) | CPU usage relative to total host cores |
| Memory Usage (%) | Memory used as a fraction of the host total |
| Memory Usage (MB) | RSS memory used by the container |
| Network In (MB) | Cumulative inbound network bytes (in MB) |
| Network Out (MB) | Cumulative outbound network bytes (in MB) |
| Restart Count | Number of times the container has restarted |
### Example: alert on high CPU
To alert when any container in a stack uses more than 80% CPU for over 5 consecutive minutes, with a 60-minute cooldown:
| Field | Value |
|-------|-------|
| Metric | CPU Usage (%) |
| Operator | Greater than |
| Threshold | 80 |
| Duration | 5 |
| Cooldown | 60 |
## Notification history
All dispatched notifications appear in the **notification bell** in the top-right corner of the navigation bar. A red dot pulses on the bell when unread notifications exist.
<Frame>
<img src="/images/alerts-notifications/notification-popover.png" alt="Notification popover showing recent alert entries with level badges and timestamps" />
</Frame>
Click the bell to open the notification popover, which shows:
- **Level badge** for each entry (ERROR in red, WARNING in amber, INFO in default)
- **Node name** badge for notifications from remote nodes
- **Timestamp** of when the alert was triggered
- **Alert message** describing what was breached
The popover header includes:
| Action | What it does |
|--------|--------------|
| **Mark all as read** | Marks all notifications as read (removes the red dot) |
| **Clear all** | Deletes all notifications from the list |
You can also dismiss individual notifications by hovering over them and clicking the dismiss button.
<Note>
Notifications only reach external channels (Discord, Slack, Webhook) if at least one channel is enabled. Dashboard notifications appear regardless.
</Note>
## Alerts on remote nodes
Alerts work the same way on remote nodes as they do locally. When you switch to a remote node and open a stack's alerts panel, you are managing rules on that remote instance.
Key details:
- **Alert rules are stored on each node independently.** Rules created while a remote node is selected are saved on that remote instance, not your primary instance.
- **Monitoring runs locally on each node.** Each Sencho instance evaluates its own alert rules against its own container metrics.
- **Notifications are sent by the node that detects the breach.** Make sure notification channels are configured on each remote node where you want to receive alerts, since channel settings are per-instance.
The alert panel shows a blue info banner when you are configuring alerts on a remote node, including which channels are active on that node.
### Setup checklist for remote alerts
You can configure a remote node's notification channels directly from the control plane:
1. From your **primary** instance, switch to the remote node using the node picker
2. Open **Settings > Notifications** and configure the remote's Discord, Slack, or Webhook channels. Values saved here apply only to the selected node.
3. Right-click a stack and select **Alerts** to create rules
4. The remote instance handles monitoring and notification delivery independently
## Update availability notifications
Sencho can notify you when software updates are available, both for Sencho itself and for your stack images.
### Sencho version updates
When a newer version of Sencho is published, an informational notification is dispatched through your configured channels. Each Sencho instance runs its own version check roughly once every 6 hours and notifies exactly once per new version, so remote nodes self-report their own availability alerts. After you update, the cycle resets and you will be notified when the next release becomes available.
The notification message includes the version you are running and the version that was detected, for example:
```
Sencho 0.47.0 is available (currently running 0.46.16). Visit the Fleet dashboard to update.
```
### Stack image updates
When the periodic image check (every 6 hours) detects that a stack has new upstream images available, a notification is dispatched for each affected stack. Notifications are sent only on state transitions: you will be notified once when an update first appears, not on every check cycle. After you update the stack, the status resets so a future release can notify again.
Both notification types use the same channel routing as alerts: if notification routes are configured for a stack, those channels receive the message; otherwise, global notification channels are used as a fallback.
## Scheduled scan completion
Recurring [vulnerability scans](/features/vulnerability-scanning) dispatch a notification whenever a run finishes so you do not have to check the task history manually.
- **Info** when every image scanned successfully.
- **Warning** when one or more images failed to scan during the run.
- **Error** when the run itself could not start (for example, Trivy is not installed on the target node).
The message includes the scheduled task name, a summary of how many images were scanned, cached, and failed, and a breakdown of findings by severity. A typical clean-run message looks like:
```
Scheduled scan "nightly-scan" completed: Scanned 12 image(s); 3 skipped (cached). Found 2 critical, 5 high, 10 medium.
```
If no critical, high, or medium findings are present, the message ends with `No critical, high, or medium findings.` so the outcome is still explicit. When the target node has nothing to scan, the message reads `No images to scan.`, and when every image was already covered by a recent cached scan it reads `All N image(s) already scanned recently (cache hit).` In both cases the notification still fires so you know the run executed.
<Note>
Severity counts reflect the current security posture of the node, aggregated across both freshly scanned images and cached scan results. They are not a delta of what changed on this run.
</Note>
Failures are typically transient (registry timeouts, missing credentials) and do not stop the rest of the run from completing.
## Container crash detection
Sencho watches every container on each of your nodes in real time and notifies you when something exits unexpectedly. Detection is causal: Sencho distinguishes crashes from intentional stops, so stopping a stack, restarting it, or running `docker compose down` will not produce a false crash alert.
### What triggers a crash alert
| Situation | Alert |
|---|---|
| Container exits with a non-zero exit code without being asked to stop | **Crash** alert (level: error) |
| Container is killed by the kernel for exceeding its memory limit | **OOM Kill** alert (level: error) |
| Healthcheck reports the container as unhealthy | **Healthcheck failed** alert (level: error) |
Alerts arrive within a couple of seconds of the event, not on a polling interval.
### What does not trigger a crash alert
- Stopping, restarting, updating, or removing a stack from Sencho
- Running `docker stop`, `docker restart`, or `docker compose down` from a terminal on the host
- A container exiting cleanly with exit code `0`
- A container being replaced during an image update
### Global toggle
Crash and unhealthy alerts are gated by the **Global Crash Detection** toggle in **Settings > System**. When disabled, Sencho stops dispatching crash and unhealthy notifications on all nodes. Stack metric alerts and update notifications are unaffected by this toggle.
### Docker daemon interruptions
If the Docker daemon becomes unreachable (daemon restart, socket lost, network issue on a remote node), Sencho sends a single **Lost connection to Docker daemon** warning and pauses crash detection on the affected node. When the connection is restored, Sencho reconciles container state against a pre-disconnect snapshot:
- If most of your containers are still running, individual gap exits are classified and alerts are sent as normal.
- If a large share of containers exited during the outage (for example after a daemon restart), Sencho consolidates them into a single **Docker daemon interruption detected** informational notification instead of paging you for every container.
A matching **Reconnected to Docker daemon** info notification confirms monitoring has resumed.
### High-churn events
When many crashes land in a short window (for example, a large stack coming down unexpectedly), Sencho dispatches an initial batch and summarizes the remainder in a single **N additional containers crashed in the last minute** entry so your notification channels are not flooded.
## Troubleshooting
### Notifications not being delivered
- Verify at least one notification channel is enabled in **Settings > Notifications**
- Click **Test** on the channel to confirm the webhook URL is reachable
- Check that the webhook URL uses HTTPS
- If using notification routing (Admiral tier), verify the route pattern matches the stack name
### Alert not firing
- Confirm the alert rule exists by opening the stack's alert panel
- Check that the **duration** has elapsed; the condition must hold continuously for the configured duration before an alert fires
- Check the **cooldown** period; after an alert fires, it will not fire again until the cooldown expires
- Verify the metric is being collected; container must be running for stats to be gathered
### I stopped a stack but got a crash alert
This should not happen. Sencho distinguishes intentional stops from crashes by correlating each container exit with the action that triggered it. If you do see a crash alert for a stack you stopped, confirm Sencho can reach the Docker daemon on the affected node: the **Lost connection to Docker daemon** warning is dispatched when the socket is unreachable, and exits observed during an outage may be classified as crashes on reconnect.
### After a Docker daemon restart I only got one summary notification
Expected. When a large share of containers exits during a Docker daemon interruption, Sencho consolidates them into a single informational notification instead of paging per container. Individual crashes that happen after the reconnect are alerted on as normal.
### Crash alerts stopped arriving and nothing else looks wrong
Check, in order:
1. Open **Settings > System** and confirm **Global Crash Detection** is on. When it is off, crash, OOM, and unhealthy notifications stop on all nodes while stack metric alerts and update notifications continue as normal.
2. Look in the in-app notifications panel for a **Lost connection to Docker daemon** warning. If present, Sencho is not receiving events from the affected node and is retrying in the background; a **Reconnected to Docker daemon** info entry will appear when monitoring resumes.
3. Confirm the affected node is reachable from the host running Sencho. For remote nodes, the remote Sencho instance is responsible for its own crash detection; check its status from that instance.
### A burst of crashes happened but I only see about twenty alerts
Expected, and by design. Sencho caps crash notifications at around 20 per minute per node so a runaway restart loop or a stack-wide failure cannot flood your notification channels. Any crashes beyond the cap in that window are rolled up into a single **N additional containers crashed in the last minute** warning. The complete, unredacted list of events is always visible in the in-app notifications panel; only external channel delivery (Discord, Slack, webhooks) is rate-limited.
### Delete confirmation dialog
Deleting an alert rule now requires confirmation. Click the trash icon next to a rule, then confirm in the dialog that appears.
### Fleet shows an update button but I never received a Sencho version notification
Fleet and the in-app bell share the same version lookup. Each Sencho instance checks for a new release roughly every 6 hours and notifies exactly once per version, so if a check already fired for the latest release the bell will not notify again for that same version.
If the update button is visible but no notification is in the bell, a transient network failure during the last successful check can briefly delay delivery; the next evaluation cycle (about every 30 seconds) retries automatically. To confirm external channels (Discord, Slack, webhooks) are reachable, open **Settings > Notifications** and click **Test** on each. The in-app bell receives every notification regardless of external channel configuration.
### A stack shows the blue update indicator but no notification was received
Open the notification bell. Dispatch failures (for example, a misconfigured Discord or Slack webhook) are logged as error entries in the bell so they are visible without tailing logs. Confirm at least one channel is enabled in **Settings > Notifications**; the in-app bell receives all notifications regardless of external channel configuration.