[19.0][FIX] queue_job: repair default_env in runjob#947
Closed
Ricardoalso wants to merge 1 commit into
Closed
Conversation
`IrHttp._auth_method_none()` forces `transaction.default_env` to an environment with `uid=None` for every `auth="none"` route, including `/queue_job/runjob`. Any `env.user` access during a savepoint-triggered flush inside a job (e.g. a recompute/constrain calling `has_group()`) then raises "Expected singleton: res.users()", since `browse(None)` is an empty recordset. Repair `default_env` to the real job-running user right after it is acquired, so any deferred computation flushed during the job's execution uses a valid environment.
Contributor
Member
|
Duplicate of #923 ? |
Author
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
IrHttp._auth_method_none()forcestransaction.default_envto an environment withuid=Nonefor everyauth="none"route, including/queue_job/runjob. Anyenv.useraccess during a savepoint-triggered flush inside a job (e.g. a recompute/constrain callinghas_group()) then raises "Expected singleton: res.users()", sincebrowse(None)is an empty recordset.Repair
default_envto the real job-running user right after it is acquired, so any deferred computation flushed during the job's execution uses a valid environment.Problem
Jobs executed through the built-in
/queue_job/runjobHTTP endpoint canintermittently — but for some jobs, deterministically — fail with:
raised from deep inside unrelated code (a
has_group()call, a computedfield, any
@api.constrainsmethod — anywhereself.env.useris accessed).The job's own code is correct; nothing in the job itself touches
env.userincorrectly. The failure happens later, during an unrelated flush.
Root cause
/queue_job/runjobis declaredauth="none". For everyauth="none"route, Odoo's
IrHttp._auth_method_none()runs before the controller body,and does this unconditionally:
This pins the transaction's
default_envto an environment withuid=None, bypassing the truthy-uid guard that normally protectsTransaction.default_envassignment (Environment.__new__,odoo/orm/environments.py).runjob()then builds its own, correctly-scoped environment(
env = http.request.env(user=SUPERUSER_ID)) and runs the job with it —but this is a different
Environmentobject. It does not touchtransaction.default_env, which stays pinned to theuid=Noneone set by_auth_method_none().The crash surfaces later because
Cursor.flush()always delegates to thetransaction's
default_env, not to whichever environment happened toschedule the pending computation:
So any deferred field computation — a stored
compute, an@api.constrainsmethod, anything reached through the generic_compute_field_value→_validate_fieldschain — that is still pendingwhen a
with cr.savepoint():block inside the job exits (which triggers animplicit flush) executes against the broken
uid=Noneenvironment. If thatcode path happens to read
self.env.user,env.userresolves tobrowse(None), an empty recordset — not a missing/inactive user, anactually empty one — and
ensure_one()(e.g. insidehas_group()) raises.Whether a given job reproduces this depends entirely on whether some
computation happens to still be pending exactly at that savepoint-exit
flush.