Wrap the entire parse_mail() call in transaction.atomic() so that all
database writes from email parsing run inside a single transaction.
The existing transaction.atomic() blocks inside parse_mail() become
savepoints within this outer transaction. The series deduplication
retry logic continues to work since savepoint rollbacks are scoped
to their own savepoint.

This also ensures that any on_commit() callbacks registered by signal
handlers only fire after the full email has been parsed and all
patch/series associations are committed.

Signed-off-by: Robin Jarry <[email protected]>
---
 patchwork/management/commands/parsemail.py                  | 4 +++-
 .../notes/parsemail-transaction-d4e5f6g7h8i9j0k1.yaml       | 6 ++++++
 2 files changed, 9 insertions(+), 1 deletion(-)
 create mode 100644 
releasenotes/notes/parsemail-transaction-d4e5f6g7h8i9j0k1.yaml

diff --git a/patchwork/management/commands/parsemail.py 
b/patchwork/management/commands/parsemail.py
index bcb257fe9714..2f90047a991b 100644
--- a/patchwork/management/commands/parsemail.py
+++ b/patchwork/management/commands/parsemail.py
@@ -8,6 +8,7 @@ import logging
 import sys
 
 from django.core.management import base
+from django.db import transaction
 
 from patchwork.parser import parse_mail
 from patchwork.parser import DuplicateMailError
@@ -57,7 +58,8 @@ class Command(base.BaseCommand):
         # broken email (ValueError):   1 (this could be noisy, if it's an issue
         #                                 we could use a different return code)
         try:
-            result = parse_mail(mail, options['list_id'])
+            with transaction.atomic():
+                result = parse_mail(mail, options['list_id'])
             if result is None:
                 logger.warning('Nothing added to database')
         except DuplicateMailError as exc:
diff --git a/releasenotes/notes/parsemail-transaction-d4e5f6g7h8i9j0k1.yaml 
b/releasenotes/notes/parsemail-transaction-d4e5f6g7h8i9j0k1.yaml
new file mode 100644
index 000000000000..37ebb0573906
--- /dev/null
+++ b/releasenotes/notes/parsemail-transaction-d4e5f6g7h8i9j0k1.yaml
@@ -0,0 +1,6 @@
+---
+fixes:
+  - |
+    Wrap the entire parse_mail() function in a single database
+    transaction to prevent partial state from being visible to
+    concurrent readers.
-- 
2.54.0

_______________________________________________
Patchwork mailing list
[email protected]
https://lists.ozlabs.org/listinfo/patchwork

Reply via email to