From 72e8e06ad33d6989a29dd8cb3b64ab89e20fd479 Mon Sep 17 00:00:00 2001 From: Thibault Francois Date: Thu, 24 Jun 2021 07:26:38 +0000 Subject: [PATCH] [FIX] crm: make lead assignation cron more resilient Use Case ======== The cron run perfectly well when there is no concurrent transaction. But in real life users may interact with leads modified in the cron. This cause two issue: Concurrent update ----------------- If a lead is modified in another transaction during a the transaction where the lead is modified. The parameter crm.assignment.commit.bundle allow to reduce the size of the transaction but before this commit the first transaction was always way longer because it took the time to handle the bundle + the fetching of all the data at the begining of the cron. The solution: start a new transaction after the preparation of the data is done Missing record -------------- If the a lead is deleted in another transaction before the transaction that modified the lead starts. The code will then try to access a record which does not exist anymore in the database causing a Cache Miss and Missing record error. The solution: Make sure a record exists in the current transaction before using it. It reduce a little bit the performance of the cron but avoiding the crashes is at this price. Discussion ---------- This commit does not remove completely the risk of crash due to concurrent update but reduce its probability a lot. To remove the risk of crash, a proper exception management should be implement in a further commit closes odoo/odoo#74166 X-original-commit: 4a70f7539ec53b9c3419f83d584ad99111d2e172 Signed-off-by: Thibault Delavallee (tde) --- addons/crm/models/crm_team.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/addons/crm/models/crm_team.py b/addons/crm/models/crm_team.py index 521c2630721..46520d02085 100644 --- a/addons/crm/models/crm_team.py +++ b/addons/crm/models/crm_team.py @@ -481,6 +481,12 @@ class Team(models.Model): population.append(team) weights.append(team.assignment_max) + # Start a new transaction, since data fetching take times + # and the first commit occur at the end of the bundle, + # the first transaction can be long which we want to avoid + if auto_commit: + self._cr.commit() + # assignment process data global_data = dict(assigned=set(), merged=set(), duplicates=set()) leads_done_ids, lead_unlink_ids, counter = set(), set(), 0 @@ -489,7 +495,7 @@ class Team(models.Model): team = random.choices(population, weights=weights, k=1)[0] # filter remaining leads, remove team if no more leads for it - teams_data[team]["leads"] = teams_data[team]["leads"].filtered(lambda l: l.id not in leads_done_ids) + teams_data[team]["leads"] = teams_data[team]["leads"].filtered(lambda l: l.id not in leads_done_ids).exists() if not teams_data[team]["leads"]: population_index = population.index(team) population.pop(population_index) @@ -553,7 +559,7 @@ class Team(models.Model): # fill cache if not already done if lead not in duplicates_cache: duplicates_cache[lead] = lead._get_lead_duplicates(email=lead.email_from) - lead_duplicates = duplicates_cache[lead] + lead_duplicates = duplicates_cache[lead].exists() if len(lead_duplicates) > 1: leads_dups_dict[lead] = lead_duplicates