feat(alerts): alert email waits 2 minutes in the outbox and each alert records its outcome (#5507)
#5507 "Alert emails through the outbox, gathered for 2 minutes" (milestone 501). Replaces the in-memory core/alert_burst.py. - outbox.hold_alert: an alert joins each recipient's held alert email, or opens one due 2 minutes later (System 156 ruling). A Postgres advisory lock keeps two alerts at once from opening two windows for one reader. - email_outbox_events.alert_json (migration 0043) keeps the alert as it fired, so the email written when the window closes says what it said. - write_held writes it then, in the reader's zone: the usual alert email for one alert, the list for several (outbox.alert_words). - after_settle records on each AlertEvent, once every email carrying it has settled: email_sent, or email_error naming each reader it didn't reach and the server's reason. - A held email survives a restart and goes out when its window closes. - A refusal of a message's one recipient no longer repeats the address. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -72,7 +72,7 @@ def test_the_sender_settles_each_row_on_what_the_server_said(app, monkeypatch):
|
||||
by = {k: rows[to[k]] for k in to}
|
||||
assert by["ok"].state == "sent" and by["ok"].sent_at is not None and by["ok"].attempts == 1
|
||||
assert by["refused"].state == "failed"
|
||||
assert by["refused"].last_error == f"{to['refused']}: 550 no such user"
|
||||
assert by["refused"].last_error == "550 no such user"
|
||||
later = by["later"]
|
||||
assert later.state == "pending" and later.attempts == 1 and later.last_error == "451 greylisted"
|
||||
assert later.next_attempt_at > later.first_attempt_at
|
||||
|
||||
Reference in New Issue
Block a user