Built-in PagerDuty-equivalent system for on-call scheduling and alert escalation. Users can now manage schedules, rotation layers, overrides, and escalation policies directly in the app alongside PagerDuty. - On-call schedules with rotation layers (daily/weekly/custom), member management, and temporary overrides - Escalation policies with ordered rules, timeout-based escalation, and user/schedule targets - Automatic escalation via Oban worker with configurable repeat count - Email notifications via Swoosh for on-call alerts - Resolver computes who's on-call from layer stacking and overrides - AlertNotificationWorker integration: starts escalation alongside PagerDuty, acknowledges/resolves incidents on alert state changes - Device and organization schemas support escalation_policy_id - Escalation policy picker on device form - Schedules nav item with tabbed index (schedules + escalation policies) - Full CRUD UI for schedules, layers, members, overrides, rules, targets - 62 LiveView tests, 56 context/schema/resolver/escalation tests - 26 E2E Playwright tests for smoke and critical path coverage
44 lines
1.1 KiB
Elixir
44 lines
1.1 KiB
Elixir
defmodule Towerops.OnCall.Notifier do
|
|
@moduledoc """
|
|
Sends on-call alert notifications to users via email.
|
|
"""
|
|
|
|
import Swoosh.Email
|
|
|
|
alias Towerops.Mailer
|
|
|
|
require Logger
|
|
|
|
@doc """
|
|
Sends an alert notification email to the given user about an incident.
|
|
"""
|
|
def notify(user, incident) do
|
|
from_address = Application.get_env(:towerops, :mailer_from, {"Towerops", "hi@towerops.net"})
|
|
|
|
email =
|
|
new()
|
|
|> to(user.email)
|
|
|> from(from_address)
|
|
|> subject("[Towerops Alert] Incident triggered")
|
|
|> text_body("""
|
|
An alert has been triggered and you are on-call.
|
|
|
|
Incident ID: #{incident.id}
|
|
Status: #{incident.status}
|
|
Triggered at: #{incident.triggered_at}
|
|
|
|
Please acknowledge or resolve this incident in Towerops.
|
|
""")
|
|
|
|
case Mailer.deliver(email) do
|
|
{:ok, _} ->
|
|
Logger.info("On-call notification sent to #{user.email} for incident #{incident.id}")
|
|
:ok
|
|
|
|
{:error, reason} ->
|
|
Logger.error("Failed to send on-call notification to #{user.email}: #{inspect(reason)}")
|
|
|
|
{:error, reason}
|
|
end
|
|
end
|
|
end
|