"""Remember which alerts are already open. Without this an alerting loop re-sends the same condition every time it runs, and a channel that cries about the same stuck event every five minutes is a channel people mute — after which it may as well not exist. One row per condition. Opened when it starts, re-notified no more often than the cooldown, and closed with a recovery notice when it clears, so nobody goes chasing something that fixed itself. Revision ID: b8d1f4a6c306 Revises: a7c9e3f5b205 """ from typing import Sequence, Union import sqlalchemy as sa from alembic import op from sqlalchemy.dialects.postgresql import UUID revision: str = "b8d1f4a6c306" down_revision: Union[str, Sequence[str], None] = "a7c9e3f5b205" branch_labels: Union[str, Sequence[str], None] = None depends_on: Union[str, Sequence[str], None] = None def upgrade() -> None: op.create_table( "alert_state", sa.Column( "id", UUID(as_uuid=True), primary_key=True, server_default=sa.text("gen_random_uuid()"), ), sa.Column("alert_key", sa.String(60), nullable=False, unique=True), sa.Column("severity", sa.String(20), nullable=False), sa.Column("detail", sa.Text(), nullable=True), sa.Column("observed", sa.Integer(), nullable=True), sa.Column( "opened_at", sa.DateTime(timezone=True), nullable=False, server_default=sa.func.now(), ), sa.Column("last_notified_at", sa.DateTime(timezone=True), nullable=True), sa.Column("notify_count", sa.Integer(), nullable=False, server_default="0"), sa.Column("resolved_at", sa.DateTime(timezone=True), nullable=True), ) op.create_index("ix_alert_state_open", "alert_state", ["resolved_at"]) def downgrade() -> None: op.drop_index("ix_alert_state_open", table_name="alert_state") op.drop_table("alert_state")