[18.0][POC] base_exception: Rollback transaction triggering exception rule#3476
[18.0][POC] base_exception: Rollback transaction triggering exception rule#3476grindtildeath wants to merge 3 commits intoOCA:18.0from
Conversation
In case a implementation module, eg sale_exception, breaks a function override, ie does not call super on sale.order.action_confirm in case an exception rule applies, it is still possible that another module that is not in the implementation module's dependency, does modify existing the same object through the same function's override that is called before through MRO. As the exception rule is only written in base_exception module, such modifications would be still be committed although the exception was triggered. The only way to rollback everything that happened is to raise an exception that is going to rollback the transaction. However, we still want to commit the write of the exception rule and not to propagate the exception back to the webclient. Since we cannot alter the env in the retrying function (that handles rollback), we do not have any other choice than to use a dedicated cursor in the dispatching function to process the request, since it could trigger the exception rule, and to use the original env to write the exception rule, and have the webclient being refreshed to display the exception. This might break the latest feature to pop up the wizard, but since this is still a POC, we could fix that afterwards in case this POC is accepted.
|
Hi @sebastienbeau, @hparfr, |
base_exception/models/ir_http.py
Outdated
| for rule_id, (model, res_ids) in to_add.items(): | ||
| old_env[model].browse(res_ids).write({"exception_ids": [(4, rule_id)]}) | ||
| for rule_id, (model, res_ids) in to_remove.items(): | ||
| old_env[model].browse(res_ids).write({"exception_ids": [(4, rule_id)]}) |
There was a problem hiding this comment.
Beware:
- in the old behavior, old rules were removed before new ones got added, while in here you do the opposite: is this a wanted change?
- the command value should be
3when removing rules,4when adding them, while in here you're always using4: can you please switch toCommand.[un]link(ID)instead to make it easier to read and debug (and also, possibly add tests)?
There was a problem hiding this comment.
Good catch, I did focus on the transaction handling, but both are valid points 👍
|
So you want to use an Why not |
|
@hparfr I'm not sure if you understood the issue here 😕 This is actually a potential fix to all of these issues:
It happened to some of our OE customers using module sale_subscription and sale_exception , when such conditions are verified:
Linked to this, #3405 is actually a workaround to avoid applying the exception for records (eg upsell orders in the example I just provided). |
No issue at all from my side. I find it "fun" to have have a true I read the code, but did not test it yet. |
| _inherit = "ir.http" | ||
|
|
||
| @classmethod | ||
| def _dispatch(cls, endpoint): |
There was a problem hiding this comment.
this will work only over an HTTP request. What about crons or other types of operations? 🤔
There was a problem hiding this comment.
Actually crons are quite tricky to handle in this context since they use their own Runner, and even in case we store the exception.rule record through a subtransaction, raising a specific error linked to this base exception module would result in the cron failing multiple times. Still, I'll check if using a subtransaction to store the exception rule and and raising an error to rollback the transaction can be handled properly in the web client as this is what prevented continuing on this alternative solution.
In case a implementation module, eg sale_exception, breaks a function override, ie does not call super on sale.order.action_confirm in case an exception rule applies, it is still possible that another module that is not in the implementation module's dependency, does modify existing the same object through the same function's override that is called before through MRO.
As the exception rule is only written in base_exception module, such modifications would be still be committed although the exception was triggered.
The only way to rollback everything that happened is to raise an exception that is going to rollback the transaction. However, we still want to commit the write of the exception rule and not to propagate the exception back to the webclient.
Since we cannot alter the env in the retrying function (that handles rollback), we do not have any other choice than to use a dedicated cursor in the dispatching function to process the request, since it could trigger the exception rule, and to use the original env to write the exception rule, and have the webclient being refreshed to display the exception.
This might break the latest feature to pop up the wizard, but since this is still a POC, we could fix that afterwards in case this POC is accepted.