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 <robin@jarry.cc>
Signed-off-by: Stephen Finucane <stephen@that.guru>
Reviewed-by: Stephen Finucane <stephen@that.guru>
[stephenfin: Slight tweaks to the release notes]
import sys
from django.core.management import base
import sys
from django.core.management import base
+from django.db import transaction
from patchwork.parser import parse_mail
from patchwork.parser import DuplicateMailError
from patchwork.parser import parse_mail
from patchwork.parser import DuplicateMailError
# broken email (ValueError): 1 (this could be noisy, if it's an issue
# we could use a different return code)
try:
# 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:
if result is None:
logger.warning('Nothing added to database')
except DuplicateMailError as exc:
--- /dev/null
+---
+fixes:
+ - |
+ Wrap the entire ``parse_mail()`` function in a single database
+ transaction to prevent partial state from being visible to
+ concurrent readers.