diff --git a/spp_attachment_av_scan/README.rst b/spp_attachment_av_scan/README.rst index 5e8c7fc23..438880b16 100644 --- a/spp_attachment_av_scan/README.rst +++ b/spp_attachment_av_scan/README.rst @@ -134,6 +134,15 @@ External: ``pyclamd`` (Python library for ClamAV integration) Changelog ========= +19.0.2.0.1 +~~~~~~~~~~ + +- fix: re-raise database errors (``psycopg2.Error``, + ``ConcurrencyError``) from the create/write scan-queue hooks instead + of swallowing them, so transient serialization failures reach Odoo's + transaction retry machinery instead of poisoning the transaction for + unrelated downstream code + 19.0.2.0.0 ~~~~~~~~~~ diff --git a/spp_attachment_av_scan/__manifest__.py b/spp_attachment_av_scan/__manifest__.py index 0d93ad2db..2af626f15 100644 --- a/spp_attachment_av_scan/__manifest__.py +++ b/spp_attachment_av_scan/__manifest__.py @@ -1,7 +1,7 @@ { # pylint: disable=pointless-statement "name": "OpenSPP Attachment Antivirus Scan", "category": "OpenSPP", - "version": "19.0.2.0.0", + "version": "19.0.2.0.1", "sequence": 1, "author": "OpenSPP.org", "website": "https://github.com/OpenSPP/OpenSPP2", diff --git a/spp_attachment_av_scan/models/ir_attachment.py b/spp_attachment_av_scan/models/ir_attachment.py index 5442e2dad..0d4a5265b 100644 --- a/spp_attachment_av_scan/models/ir_attachment.py +++ b/spp_attachment_av_scan/models/ir_attachment.py @@ -3,11 +3,29 @@ import json import logging +import psycopg2 + from odoo import Command, _, api, fields, models -from odoo.exceptions import AccessError, UserError +from odoo.exceptions import AccessError, ConcurrencyError, UserError _logger = logging.getLogger(__name__) +#: Queueing a malware scan is best-effort — a scan that cannot be enqueued must not +#: block the attachment write. A **database** error is categorically different: it +#: leaves the transaction unusable, so swallowing one converts a recoverable fault +#: into an unrelated failure somewhere downstream. +#: +#: This is a superset of the classes ``odoo.service.model.retrying`` recovers from +#: by rolling back and re-running the request (``IntegrityError``, ``OperationalError``, +#: ``ConcurrencyError`` — see ``odoo/service/model.py``); the non-retryable rest of +#: ``psycopg2.Error`` then surfaces with the true traceback instead of poisoning +#: downstream code. ``SerializationFailure`` +#: resolves through that tuple via +#: ``SerializationFailure -> TransactionRollbackError -> OperationalError``, so a +#: concurrent-update conflict on an attachment is retried transparently — *unless* +#: something catches it first. +_MUST_NOT_SWALLOW = (psycopg2.Error, ConcurrencyError) + QUARANTINE_PROVIDER_PARAM = "spp_attachment_av_scan.quarantine_encryption_provider_id" QUARANTINE_RETENTION_DAYS_PARAM = "spp_attachment_av_scan.quarantine_retention_days" DEFAULT_QUARANTINE_RETENTION_DAYS = 90 @@ -92,6 +110,11 @@ def create(self, vals_list): priority=20, )._scan_for_malware() _logger.info("Queued malware scan for attachment ID %s", attachment.id) + except _MUST_NOT_SWALLOW: + # Never swallow: see ``_MUST_NOT_SWALLOW``. Re-raise so the + # request is rolled back and retried instead of continuing on a + # dead transaction. + raise except Exception as error: _logger.error( "Failed to queue malware scan for attachment ID %s: %s", @@ -130,6 +153,14 @@ def write(self, vals): "Queued malware scan for updated attachment ID %s", attachment.id, ) + except _MUST_NOT_SWALLOW: + # Never swallow: see ``_MUST_NOT_SWALLOW``. This is the exact + # site that turned a transient "could not serialize access due + # to concurrent update" on an attachment into an + # InFailedSqlTransaction reported from an unrelated menu-icon + # lookup, on every module upgrade, with the real cause visible + # only as a stray ERROR line in the server log. + raise except Exception as error: _logger.error( "Failed to queue malware scan for updated attachment ID %s: %s", diff --git a/spp_attachment_av_scan/readme/HISTORY.md b/spp_attachment_av_scan/readme/HISTORY.md index 4aaf9afef..246432337 100644 --- a/spp_attachment_av_scan/readme/HISTORY.md +++ b/spp_attachment_av_scan/readme/HISTORY.md @@ -1,3 +1,10 @@ +### 19.0.2.0.1 + +- fix: re-raise database errors (`psycopg2.Error`, `ConcurrencyError`) from the + create/write scan-queue hooks instead of swallowing them, so transient + serialization failures reach Odoo's transaction retry machinery instead of + poisoning the transaction for unrelated downstream code + ### 19.0.2.0.0 - Initial migration to OpenSPP2 diff --git a/spp_attachment_av_scan/static/description/index.html b/spp_attachment_av_scan/static/description/index.html index 2b113b66f..426e71d7e 100644 --- a/spp_attachment_av_scan/static/description/index.html +++ b/spp_attachment_av_scan/static/description/index.html @@ -515,6 +515,16 @@

Changelog

+

19.0.2.0.1

+ +
+

19.0.2.0.0