Problem/Motivation

The SELECT-before-INSERT sequence has no unique database constraint. Two concurrent requests can both observe no row and insert a duplicate. The message_id schema entry is only a nonunique index.

Evidence and scope

Reviewed 1.0.0-alpha1, source commit 02fd9d36af5237e712cecb7155d79725f7824880. Location: src/Controller/PostmarkWebhookController.php:77.

Code-confirmed interleaving; no concurrent load reproduction was run. The existing sequential retry test cannot verify concurrency safety.

Proposed resolution

After event identity is corrected, add a portable unique event key and handle only the expected duplicate-key conflict as an acknowledged retry. Preserve unexpected database failures for retry; do not turn all write exceptions into 200.

Acceptance criteria

Exercise simultaneous identical requests against supported databases; exactly one durable event and both successful acknowledgements. Test unrelated database failures and upgrade existing duplicate rows.

Comments

jmcerda created an issue. See original summary.

jmcerda’s picture

Assigned: Unassigned » jmcerda
Status: Active » Needs review

Implemented together with #3621119 in https://git.drupalcode.org/project/postmark_webhooks/-/merge_requests/1 . A unique event key replaces SELECT-before-INSERT. Both PostgreSQL test matrices (Drupal 10.3/PHP 8.3 and Drupal 11/PHP 8.4) pass 26 tests and 77 assertions, including two independent simultaneous receiver processes returning 200 with one durable row. Legacy duplicates are preserved and unrelated integrity errors propagate. Coding standards pass.

jmcerda’s picture

Status: Needs review » Fixed

Atomic retry handling was integrated with event identity in development commit 69e045b and is included in the current 1.x head d3c5d94. The development branch is mirrored to Drupalcode, and matching remote heads were verified. Independent concurrent receiver and rollback tests cover this behavior. Marking Fixed on the development branch; no release tag or deployment is recorded by this update.

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.