Skip to content

[20.0][MIG] queue_job: Migration to 20.0 - #999

Open
dhongu wants to merge 22 commits into
OCA:20.0from
dhongu:20.0-mig-queue_job
Open

dhongu wants to merge 22 commits into
OCA:20.0from
dhongu:20.0-mig-queue_job

Conversation

@dhongu

@dhongu dhongu commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

Migration of queue_job to Odoo 20.0.

Main changes:

  • ir.model.access + ir.rule → ir.access
  • registry.clear_cache → transaction.invalidate_ormcache
  • controller: use odoo.sql_db.PG_CONCURRENCY_EXCEPTIONS_TO_RETRY (odoo.service.model was removed); env.clear() → env.transaction.clear()
  • jobrunner: odoo.modules.db.list_dbs (odoo.service.db was removed)
  • fields: _setup_attrs → _setup_attrs__; tools.ormcache → api.ormcache
  • JS: job_direct_graph widget ported to Owl 3 (useProps, signal ref)
  • views: remaining_days widget → relative_date; stat button icon
  • tests: odoo.http.Request → odoo.http.requestlib.Request
  • Domain.custom(to_sql=...) takes a single table argument; concat() takes a single iterable
  • lint fixes required by the 20.0 template (ruff 0.16.8, pylint-odoo 10): a few small refactors, and # noqa: DTZ005 on datetime.now() because Odoo stores naive UTC datetimes

Tested locally on Odoo 20.0 with PostgreSQL 16: the module installs and all 59 queue_job tests pass (197 together with test_queue_job, #1021). pre-commit run -a is clean.

This PR also includes the work prepared by @jaredkipe in #997 (co-authored).

The history includes all the queue_job commits of 19.0 up to now (channel pause, autovacuum, cancellation of dependent jobs, ...).

test_queue_job is migrated in #1021 (stacked on this PR); the other addons will follow in separate PRs.

Assisted-by: Claude Opus 5.5

@oca-cla-bot

oca-cla-bot Bot commented Sep 28, 2026 •

Copy link
Copy Markdown

All commit authors signed the Contributor License Agreement.

CLA signed

@Reyes4711-S73

Copy link
Copy Markdown

@BhaveshHeliconia BhaveshHeliconia left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @dhongu for working on this!

While testing, I found that clicking another job in the Dependencies tab raises an error because get_formview_action() was removed in Odoo 20.0.

Fix: build the form action directly in JS instead of asking the server, then pass it to this.action.doAction(). I tried this locally and the click opens the job correctly.

@micheledic micheledic left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding to this, you should preserve the full history.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"get_record_default_action",

@dhongu

dhongu commented Oct 16, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the reviews, both points are addressed:

  • History: the branch is rebuilt following the 20.0 migration guide (git format-patch ... origin/20.0..origin/19.0 -- queue_job | git am -3 --keep). The 19.0 commits merged after the 20.0 branch was created are now included (JobSerialized base_type validation, on-fail hook deadlock, jobrunner in odoo shell), followed by a [IMP] pre-commit auto fixes commit and the [MIG] commit.
  • Dependencies tab: get_formview_action → get_record_default_action, as suggested by @micheledic. Thanks @BhaveshHeliconia for the report.

pre-commit run -a is clean and all 56 queue_job tests pass locally on Odoo 20.0.

@BhaveshHeliconia BhaveshHeliconia left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@BhaveshHeliconia

Copy link
Copy Markdown

You shouldn't add the AI agent as a co-author. It should be mentioned as assisted by AI according to the OCA AI policy: https://github.com/OCA/.github/blob/master/AI_POLICY.md

@miguel-S73

Copy link
Copy Markdown

LGTM!

@dhongu
dhongu force-pushed the 20.0-mig-queue_job branch from 2b08ccd to 33c10a8 Compare October 19, 2026 11:29
@dhongu

dhongu commented Oct 19, 2026

Copy link
Copy Markdown
Contributor Author

Thanks @BhaveshHeliconia, good point. The migration commit now uses an Assisted-by: Claude Opus 5.5 trailer instead of Co-authored-by, in line with the OCA AI policy, and the PR description is updated accordingly. Only the commit message changed; the code is identical.

@alan196 alan196 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Functional Review LGTM 👍

@ristecona

Copy link
Copy Markdown

Tested on Odoo 20.0 (OCB at 1ab6b915 with the Enterprise addons) at the head of this branch (33c10a8). queue_job installs on a clean database and all 56 tests pass.

One note for completeness: when the website module is installed in the same database, TestRunJobHttp.test_runjob_without_updating_default_env_leaves_uid_none fails with a 500. The server log shows KeyError: 'host_id' in website/models/ir_http.py (_generate_routing_rules), raised while the routing map is built for the first request of an HttpCase. It is not caused by this migration, and the test passes without website, which is how the CI runs.

I also used it for a health check that looks at stuck queue.job records (state, date_enqueued, date_started), and it behaves as on 19.0.

Tested with the help of Claude Code (AI assisted).

@guewen

guewen commented Oct 26, 2026

Copy link
Copy Markdown
Member

Thanks for the migration work @dhongu. The test_queue_job is there to guarantees the behavior of queue_job is correct, so we cannot merge queue_job alone. Did you start some work on that or plan to?

Comment thread queue_job/jobrunner/channels.py Outdated
"""

__slots__ = ("db_name", "channel", "uuid", "_sorting_key", "__weakref__")
__slots__ = ("__weakref__", "_sorting_key", "channel", "db_name", "uuid")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason for changing this?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No functional reason: ruff (RUF023) reordered __slots__ alphabetically under the 20.0 template. I restored the original order with # noqa: RUF023, so the line is now identical to 19.0 apart from the noqa.

Comment thread queue_job/jobrunner/runner.py Outdated
# stop-pipe is not a conn so doesn't need poll()
continue
key.fileobj.poll()
if timeout > 0 and conns and not self._stop:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like only a cosmetic only change, that will make the backward/forward porting conflict.
Not really necessary for the migration

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. This was a ruff autofix (SIM102). I restored the nested if blocks exactly as on 19.0 and added # noqa: SIM102, so this block no longer differs from 19.0 and will not cause conflicts in forward/backward ports.

@dhongu
dhongu force-pushed the 20.0-mig-queue_job branch from 33c10a8 to ce7926d Compare October 27, 2026 05:59
guewen and others added 4 commits October 27, 2026 08:01
Add a new "paused" option on channel configuration.
A paused channel is equivalent to a channel with no capacity:
it yields no job and also blocks all its subchannels.

It still needs a restart of the jobrunner, so it does not allow dynamic
pause/resume, but hot reload may be added later in OCA#765.

It still is an improvement over setting the capacity at 0, because it
keeps the capacity in the configuration (removing the option in the
config restores the initial capacity).
Odoo 19 renamed Field._setup_attrs to _setup_attrs__, so the override
was no longer called and an unsupported base_type was silently accepted.
In Odoo 19 res.users.group_ids only holds explicitly assigned groups;
implied ones are exposed through all_group_ids. Users who got Job Queue
Manager through another group were no longer subscribed to failed jobs.
ivantodorovich and others added 17 commits October 27, 2026 08:01
The failure is handled from a temporary cursor while the failed job's
transaction still holds its locks: an on fail hook writing on the same
records waited forever. Perform the job in a savepoint so that its
locks are released when it fails.
odoo shell starts the server with stop=True and stops it right away, so the
runner thread was started for nothing and its START_DELAY made every shell
wait 5 seconds before the prompt. Core already skips its HTTP and cron threads
when stop is set; the runner now follows the same rule.
A runner that lost the master election, or hit an error, slept
ERROR_RECOVERY_DELAY with time.sleep, and the start delay slept
START_DELAY the same way. stop() could not interrupt either, and the
server joins the runner thread on shutdown, so the whole process waited
up to 5 seconds. On hosts that kill a process a few seconds after asking
it to stop, a process whose runner was not the master was killed instead
of exiting.

Both delays now wait on an event that stop() sets.
Neutralized databases disable every cron except the base autovacuum,
so old jobs were never removed there. Replace the dedicated cron with
an @api.autovacuum method, deleting in batches of 1000.
Updated by "Update PO files to match POT (msgmerge)" hook in Weblate.

Translation: queue-19.0/queue-19.0-queue_job
Translate-URL: https://translation.odoo-community.org/projects/queue-19-0/queue-19-0-queue_job/
- Cancelling a job now cancels its dependents all the way down. Before,
  only direct dependents were cancelled: in A -> B -> C, cancelling A
  left C waiting forever.
  Test: test_button_cancel_dependencies_cascade
- A job is cancelled as soon as one of its dependencies is cancelled.
  Before, it was only cancelled when all of them were, so a job with one
  cancelled and one done (or running) dependency waited forever.
  Tests: test_button_cancel_dependencies_other_parent_done,
  test_button_done_dependencies_other_parent_cancelled
- Cancelled dependents get a date_cancelled, the same as the cancelled
  job. It was left empty, so the autovacuum never removed them.
  Tests: test_button_cancel_dependencies,
  test_button_cancel_dependencies_cascade
- Cancelled dependents get a result telling why they were cancelled.
  Tests: test_button_cancel_dependencies_cascade,
  test_button_cancel_dependencies_selected
- Cancelling a job along with its dependent cancels the dependent once.
  Before, it was cancelled a second time as part of the selection,
  overwriting its date and result.
  Test: test_button_cancel_dependencies_selected

_get_common_dependent_jobs_query is replaced by the searchable
dependency_ids and dependent_ids computed fields on queue.job, used to
enqueue and cancel dependent jobs through the ORM.
Test: test_search_dependencies
Updated by "Update PO files to match POT (msgmerge)" hook in Weblate.

Translation: queue-19.0/queue-19.0-queue_job
Translate-URL: https://translation.odoo-community.org/projects/queue-19-0/queue-19-0-queue_job/
@dhongu
dhongu force-pushed the 20.0-mig-queue_job branch from ce7926d to 41aff81 Compare October 27, 2026 06:04
- ir.model.access + ir.rule -> ir.access
- registry.clear_cache -> transaction.invalidate_ormcache
- controller: use odoo.sql_db.PG_CONCURRENCY_EXCEPTIONS_TO_RETRY
  (odoo.service.model was removed); env.clear() -> env.transaction.clear()
- jobrunner: odoo.modules.db.list_dbs (odoo.service.db was removed)
- fields: _setup_attrs -> _setup_attrs__; tools.ormcache -> api.ormcache
- JS: job_direct_graph widget ported to Owl 3 (useProps, signal ref);
  get_formview_action -> get_record_default_action (removed in 20.0)
- views: remaining_days widget -> relative_date; stat button icon
- tests: odoo.http.Request -> odoo.http.requestlib.Request
- `Domain.custom(to_sql=...)` now takes a single `table` argument
- `concat()` takes a single iterable
- lint fixes required by the 20.0 template (ruff 0.16, pylint-odoo 10)

Co-authored-by: Jared Kipe <jared@hibou.io>
Assisted-by: Claude Opus 5.5

@florentx florentx Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to repeat the typo from the [19.0] branch. (in filename)

(to be changed in tests/__init__.py too)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.