mirror of
https://github.com/Studio-Saelix/sencho.git
synced 2026-08-25 17:57:06 +00:00
feat(notifications): add shared notification routing rules (Admiral tier) (#347)
Route stack alerts to specific Discord, Slack, or webhook channels instead of the single global endpoint. Includes per-rule enable/disable, priority ordering, and automatic fallback to global agents when no rule matches. - Add notification_routes table, interface, and CRUD in DatabaseService - Add routing logic in NotificationService.dispatchAlert with optional stackName - Pass stack context from MonitorService (crash/health) and SchedulerService - Add 5 API endpoints gated with requireAdmin + requireAdmiral - Add NotificationRoutingSection UI with Combobox stack picker, channel tabs - Parallel webhook dispatch via Promise.allSettled - 10 unit tests covering routing, fallback, and edge cases - Documentation with screenshots at docs/features/notification-routing.mdx
This commit is contained in:
@@ -128,17 +128,18 @@ export class MonitorService {
|
||||
const containers = await docker.getAllContainers();
|
||||
for (const c of containers) {
|
||||
if (c.State === 'exited' || String(c.Status).includes('unhealthy')) {
|
||||
const containerStack = c.Labels?.['com.docker.compose.project'] || undefined;
|
||||
if (c.State === 'exited') {
|
||||
if (c.Status.includes('seconds ago')) {
|
||||
const match = c.Status.match(/Exited \((\d+)\)/i);
|
||||
const exitCode = match ? parseInt(match[1], 10) : null;
|
||||
const intentionalExitCodes = [0, 137, 143, 255];
|
||||
if (exitCode !== null && !intentionalExitCodes.includes(exitCode)) {
|
||||
await notifier.dispatchAlert('error', `[Node: ${node.name}] Container Crash Detected: ${c.Names[0]} exited unexpectedly (Code: ${exitCode}).`);
|
||||
await notifier.dispatchAlert('error', `[Node: ${node.name}] Container Crash Detected: ${c.Names[0]} exited unexpectedly (Code: ${exitCode}).`, containerStack);
|
||||
}
|
||||
}
|
||||
} else if (String(c.Status).includes('unhealthy')) {
|
||||
await notifier.dispatchAlert('error', `[Node: ${node.name}] Healthcheck Failed: Container ${c.Names[0]} is unhealthy.`);
|
||||
await notifier.dispatchAlert('error', `[Node: ${node.name}] Healthcheck Failed: Container ${c.Names[0]} is unhealthy.`, containerStack);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -277,7 +278,8 @@ export class MonitorService {
|
||||
|
||||
await NotificationService.getInstance().dispatchAlert(
|
||||
'warning',
|
||||
message
|
||||
message,
|
||||
rule.stack_name
|
||||
);
|
||||
|
||||
// Update last fired
|
||||
|
||||
Reference in New Issue
Block a user