fix: async newsletter emails, migration locking, webhook signature enforcement, DLQ metric - #829
Merged
Merged
Conversation
…er confirmation email Newsletter subscription emails are already enqueued via email/queue.rs. Changed the response status from 200 OK to 202 Accepted to accurately reflect that the request was accepted for async processing, not completed inline. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…SQL advisory lock MigrationRunner::run() now acquires a session-level advisory lock via pg_try_advisory_lock before executing any migrations. If another instance already holds the lock the call aborts with a clear error, causing startup to fail rather than running duplicate migrations. The lock is always released (even on failure) before the connection returns to the pool to avoid leaking it across pool reuse. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ONMENT is unset The sendgrid_webhook_middleware defaulted is_dev to true when the ENVIRONMENT variable was absent, which silently bypassed signature verification for any deployment that did not explicitly set the variable. Changed the default to false so that signature verification is enforced unless ENVIRONMENT=development is explicitly configured. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…s gauge Added email_dlq_size IntGauge to the Metrics registry. The gauge is updated each time the email_queue_stats endpoint is called, reflecting the current Redis DLQ (email:dead_letter) cardinality. The existing list_dead_letter and requeue_dead_letter methods plus their admin HTTP endpoints satisfy the inspect-and-replay acceptance criterion. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
@Fidelis900 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR resolves four backend reliability and security issues across the email and migration subsystems.
fix(#677) — Newsletter confirmation email is now non-blocking
File:
services/api/src/handlers.rsThe
newsletter_subscribehandler was already enqueuing confirmation emails viaemail/queue.rs, but still returned200 OK— implying the operation had completed synchronously. Changed the response to202 Acceptedso the status code accurately reflects that the email has been accepted for asynchronous processing, not sent inline. This also aligns the endpoint with REST semantics for async operations.fix(#676) — Migrations are now serialized with a PostgreSQL advisory lock
File:
services/api/src/migrations.rsIn a horizontally scaled deployment, multiple instances starting simultaneously could each call
MigrationRunner::run()concurrently, resulting in duplicate or conflicting migration attempts.run()now:pg_try_advisory_lockon a stable key (0x707265646963_7471) before executing any migrations.pg_advisory_unlockbefore the connection is returned to the pool (both on success and failure), preventing the lock from leaking across pool-reused connections.The migration logic itself is extracted into a private
run_inner()to keep the locking and execution concerns separate.fix(#679) — Webhook HMAC signature verification is now enforced by default
File:
services/api/src/security.rssendgrid_webhook_middlewaredetermined whether to run in development mode (bypassing signature verification) via:If the
ENVIRONMENTenvironment variable was absent — which is common in staging or misconfigured production deployments — the middleware silently skipped HMAC verification, allowing any party to forge webhook events. Changed the default tofalseso that signature verification is enforced unlessENVIRONMENT=developmentis explicitly set.fix(#678) — DLQ size exposed as a Prometheus gauge
Files:
services/api/src/metrics.rs,services/api/src/handlers.rsThe dead-letter queue (Redis key
email:dead_letter) had no observability. Added anemail_dlq_sizeIntGaugeto theMetricsregistry. The gauge is updated each time theGET /api/v1/email/queue/statsendpoint is called, reflecting the current DLQ cardinality from Redis.The existing
list_dead_letter(GET /api/v1/email/dead-letter) andrequeue_dead_letter(POST /api/v1/email/dead-letter/:id/requeue) admin endpoints satisfy the inspect-and-replay acceptance criterion — no new endpoints were needed.Closes
Closes #677
Closes #676
Closes #679
Closes #678
🤖 Generated with Claude Code