prop/priv/repo/migrations/20260402212323_add_enrichment_notify_triggers.exs
Graham McIntire 33171ab32e
Replace polling with Postgres LISTEN/NOTIFY for live updates
- Database triggers on contacts and oban_jobs fire pg_notify on
  status/state changes
- RepoListener GenServer subscribes via Postgrex.Notifications and
  broadcasts to PubSub
- Backfill dashboard subscribes to PubSub instead of 2-second polling
- Eliminates periodic SELECT queries, updates arrive instantly
2026-04-02 16:26:22 -05:00

62 lines
1.9 KiB
Elixir

defmodule Microwaveprop.Repo.Migrations.AddEnrichmentNotifyTriggers do
use Ecto.Migration
def up do
# Notify on contact enrichment status changes
execute """
CREATE OR REPLACE FUNCTION notify_contact_status_change() RETURNS trigger AS $$
BEGIN
IF OLD.hrrr_status IS DISTINCT FROM NEW.hrrr_status
OR OLD.weather_status IS DISTINCT FROM NEW.weather_status
OR OLD.terrain_status IS DISTINCT FROM NEW.terrain_status
OR OLD.iemre_status IS DISTINCT FROM NEW.iemre_status THEN
PERFORM pg_notify('contact_status_changed', json_build_object(
'id', NEW.id,
'hrrr_status', NEW.hrrr_status,
'weather_status', NEW.weather_status,
'terrain_status', NEW.terrain_status,
'iemre_status', NEW.iemre_status
)::text);
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
"""
execute """
CREATE TRIGGER contact_status_notify
AFTER UPDATE ON contacts
FOR EACH ROW EXECUTE FUNCTION notify_contact_status_change();
"""
# Notify on Oban job state changes
execute """
CREATE OR REPLACE FUNCTION notify_oban_job_change() RETURNS trigger AS $$
BEGIN
IF OLD.state IS DISTINCT FROM NEW.state THEN
PERFORM pg_notify('oban_job_changed', json_build_object(
'id', NEW.id,
'worker', NEW.worker,
'queue', NEW.queue,
'state', NEW.state
)::text);
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
"""
execute """
CREATE TRIGGER oban_job_notify
AFTER UPDATE ON oban_jobs
FOR EACH ROW EXECUTE FUNCTION notify_oban_job_change();
"""
end
def down do
execute "DROP TRIGGER IF EXISTS contact_status_notify ON contacts"
execute "DROP FUNCTION IF EXISTS notify_contact_status_change()"
execute "DROP TRIGGER IF EXISTS oban_job_notify ON oban_jobs"
execute "DROP FUNCTION IF EXISTS notify_oban_job_change()"
end
end