From cfa20f3effc87ffcc21d282cee558da7343824bf Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Fri, 9 Oct 2020 08:11:31 +0000 Subject: [PATCH] [FIX] hr_work_entry: stop shadowing concurrent updates The `_error_checking()` context manager is used to perform validation and cleanup after changes on work entries, and is implemented using a try/finally clause. This mechanism fails to take into account that the alteration operation can fail due to a concurrent update (in another transaction). In such a situation the db cursor becomes instantly invalid, and any attempt to use it will fail with: `psycopg2.InternalError: current transaction is aborted`. This exception will be raised in the `finally` block, and will therefore discard the original TransactionRollbackException. The result: instead of being silently retried as expected, the transaction fails and the user receives a cryptic error message. Steps to repro: repeatedly click on the button to validate a leave Solution: specifically handle PostgreSQL `OperationalError` exceptions and do not attempt to use the cursor when they occur - just let the exception bubble up. closes odoo/odoo#59612 X-original-commit: 7ba47e7215df69b6556a848532e4f33ef4243e83 Signed-off-by: Yannick Tivisse (yti) --- addons/hr_work_entry/models/hr_work_entry.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/addons/hr_work_entry/models/hr_work_entry.py b/addons/hr_work_entry/models/hr_work_entry.py index 4484bb443cc..10f737315eb 100644 --- a/addons/hr_work_entry/models/hr_work_entry.py +++ b/addons/hr_work_entry/models/hr_work_entry.py @@ -3,6 +3,7 @@ from contextlib import contextmanager from dateutil.relativedelta import relativedelta +from psycopg2 import OperationalError from odoo import api, fields, models @@ -169,6 +170,11 @@ class HrWorkEntry(models.Model): ]) work_entries._reset_conflicting_state() yield + except OperationalError: + # the cursor is dead, do not attempt to use it or we will shadow the root exception + # with a "psycopg2.InternalError: current transaction is aborted, ..." + skip = True + raise finally: if not skip and start and stop: # New work entries are handled in the create method,