Skip to content

Commit c602e65

Browse files
authored
Retry failed emails (#1650)
* Retry failed emails * Upsert course instance enrollments * Fixes * Fixes * Fixes
1 parent 5015fb8 commit c602e65

18 files changed

+826
-162
lines changed
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
DROP INDEX IF EXISTS email_deliveries_retry_queue_idx;
2+
DROP INDEX IF EXISTS email_delivery_errors_created_at_idx;
3+
DROP INDEX IF EXISTS email_delivery_errors_email_delivery_id_idx;
4+
5+
DROP TRIGGER IF EXISTS set_timestamp ON email_delivery_errors;
6+
7+
DROP TABLE IF EXISTS email_delivery_errors;
8+
9+
ALTER TABLE email_deliveries
10+
DROP COLUMN IF EXISTS last_attempt_at,
11+
DROP COLUMN IF EXISTS first_failed_at,
12+
DROP COLUMN IF EXISTS retryable,
13+
DROP COLUMN IF EXISTS next_retry_at,
14+
DROP COLUMN IF EXISTS retry_count,
15+
ADD COLUMN error VARCHAR(255) DEFAULT NULL;
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
-- Email delivery retries
2+
ALTER TABLE email_deliveries
3+
ADD COLUMN retry_count INT NOT NULL DEFAULT 0,
4+
ADD COLUMN next_retry_at TIMESTAMPTZ NULL,
5+
ADD COLUMN retryable BOOLEAN NOT NULL DEFAULT TRUE,
6+
ADD COLUMN first_failed_at TIMESTAMPTZ NULL,
7+
ADD COLUMN last_attempt_at TIMESTAMPTZ NULL;
8+
9+
UPDATE email_deliveries
10+
SET retryable = FALSE
11+
WHERE sent = FALSE
12+
AND error IS NOT NULL;
13+
14+
ALTER TABLE email_deliveries
15+
DROP COLUMN IF EXISTS error;
16+
17+
CREATE TABLE email_delivery_errors (
18+
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
19+
email_delivery_id UUID NOT NULL REFERENCES email_deliveries (id) ON DELETE CASCADE,
20+
attempt INT NOT NULL,
21+
error_message TEXT NOT NULL,
22+
error_code TEXT NULL,
23+
smtp_response TEXT NULL,
24+
smtp_response_code INT NULL,
25+
is_transient BOOLEAN NOT NULL,
26+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
27+
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
28+
deleted_at TIMESTAMPTZ NULL
29+
);
30+
31+
CREATE TRIGGER set_timestamp BEFORE
32+
UPDATE ON email_delivery_errors FOR EACH ROW EXECUTE PROCEDURE trigger_set_timestamp();
33+
34+
CREATE INDEX email_delivery_errors_email_delivery_id_idx ON email_delivery_errors (email_delivery_id);
35+
36+
CREATE INDEX email_delivery_errors_created_at_idx ON email_delivery_errors (created_at);
37+
38+
CREATE INDEX email_deliveries_retry_queue_idx ON email_deliveries (next_retry_at)
39+
WHERE sent = FALSE
40+
AND retryable = TRUE
41+
AND deleted_at IS NULL;
42+
43+
COMMENT ON TABLE email_delivery_errors IS 'Log of individual email delivery failures.';
44+
45+
COMMENT ON COLUMN email_delivery_errors.id IS 'Stable identifier for an individual email delivery error entry.';
46+
47+
COMMENT ON COLUMN email_delivery_errors.email_delivery_id IS 'Foreign key to the parent email_deliveries row this error belongs to.';
48+
49+
COMMENT ON COLUMN email_delivery_errors.attempt IS '1-based send attempt number at which this error occurred.';
50+
51+
COMMENT ON COLUMN email_delivery_errors.error_message IS 'Human-readable description of the failure returned by the mailer or application.';
52+
53+
COMMENT ON COLUMN email_delivery_errors.error_code IS 'Short machine-friendly classification of the failure (e.g. transient, permanent, timeout).';
54+
55+
COMMENT ON COLUMN email_delivery_errors.smtp_response IS 'Raw SMTP response text associated with the failure when available.';
56+
57+
COMMENT ON COLUMN email_delivery_errors.smtp_response_code IS 'Numeric SMTP status code associated with the failure when available.';
58+
59+
COMMENT ON COLUMN email_delivery_errors.is_transient IS 'Indicates whether the failure is considered transient and therefore retryable.';
60+
61+
COMMENT ON COLUMN email_delivery_errors.created_at IS 'Timestamp when this email delivery error entry was recorded.';
62+
63+
COMMENT ON COLUMN email_delivery_errors.updated_at IS 'Timestamp when this email delivery error entry was last updated. The field is updated automatically by the set_timestamp trigger.';
64+
65+
COMMENT ON COLUMN email_delivery_errors.deleted_at IS 'Timestamp when this email delivery error entry was soft deleted.';
66+
67+
COMMENT ON COLUMN email_deliveries.retry_count IS 'Number of failed delivery attempts recorded so far for this email.';
68+
69+
COMMENT ON COLUMN email_deliveries.next_retry_at IS 'Next scheduled time when this email delivery will be retried, or NULL when no retry is scheduled.';
70+
71+
COMMENT ON COLUMN email_deliveries.retryable IS 'Indicates whether this email delivery is still eligible for further retry attempts.';
72+
73+
COMMENT ON COLUMN email_deliveries.first_failed_at IS 'Timestamp of the first failed delivery attempt for this email, used as the retry window anchor.';
74+
75+
COMMENT ON COLUMN email_deliveries.last_attempt_at IS 'Timestamp of the most recent delivery attempt for this email.';

services/headless-lms/models/.sqlx/query-16e3c3709cc4ececf60df6f6780dfff6b4efbc148dc5ba5d79886a009a7b6e2f.json

Lines changed: 0 additions & 62 deletions
This file was deleted.

services/headless-lms/models/.sqlx/query-2979e4b63ac9f1c3499564b51e32ba4b81b77166bc1eb78ffe64aee448367310.json

Lines changed: 29 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

services/headless-lms/models/.sqlx/query-0cb6f9e6d5c8bc8f0196ec503ba5654ac5af8fc3e61746ddcadc30668bca65eb.json renamed to services/headless-lms/models/.sqlx/query-2b4dfc81801997749eb2c598bb5a0c89787d186b9644871b1a5a460af3697396.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

services/headless-lms/models/.sqlx/query-8e2c2b4da1778edef5957fd1bd95ce5ce1d38a8b855a91cb2fb77bb2c72a619f.json

Lines changed: 94 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

services/headless-lms/models/.sqlx/query-94ef6a94b772899bbcb944338c13d00bb4d10af5106dde5398c7cee85b3528ba.json

Lines changed: 14 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

services/headless-lms/models/.sqlx/query-94f731505415d7fe7575cbe5834ec69f748138ec956ae2a20ed4018a54e9fcca.json

Lines changed: 21 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

services/headless-lms/models/.sqlx/query-ab3e3cd05607b5954fca7901d470d3ca3ee25458e3876c4b3a2b1564b96df90a.json

Lines changed: 14 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

services/headless-lms/models/.sqlx/query-d309be59564d69ecad6e11cc6976649092966ea2236abd7c8ca72e64f78f8fcc.json

Lines changed: 0 additions & 14 deletions
This file was deleted.

0 commit comments

Comments
 (0)