Skip to content

[17.0] queue_job: concurrent update exception on job state update #879

@m3asmi

Description

@m3asmi

hi,
I found issue with latest version of queue_job '17.0.1.5.0'

 2026-01-15 16:33:37,264 2391938 ERROR tecnibo170 odoo.addons.queue_job.controllers.main: PG concurrency error (40001) while performing job. uuid=d665ad65-1df5-4679-8d59-dd33c41f9d72 func=imos.proadmin(15267,).create_sub_so() pid=2392431 

Traceback (most recent call last):

  File "/home/rachid/01_Workspace/odoo/custom/other_addons/queue_job/controllers/main.py", line 122, in runjob

    self._try_perform_job(env, job)

  File "/home/rachid/01_Workspace/odoo/custom/other_addons/queue_job/controllers/main.py", line 44, in _try_perform_job

    env.flush_all()

  File "/home/rachid/01_Workspace/odoo/servers/17/odoo/api.py", line 739, in flush_all

    self[model_name].flush_model()

  File "/home/rachid/01_Workspace/odoo/servers/17/odoo/models.py", line 6364, in flush_model

    self._flush(fnames)

  File "/home/rachid/01_Workspace/odoo/servers/17/odoo/models.py", line 6466, in _flush

    model.browse(ids)._write(vals)

  File "/home/rachid/01_Workspace/odoo/servers/17/odoo/models.py", line 4550, in _write

    cr.execute(SQL(

  File "/home/rachid/01_Workspace/odoo/servers/17/odoo/sql_db.py", line 335, in execute

    res = self._obj.execute(query, params)

          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

psycopg2.errors.SerializationFailure: could not serialize access due to concurrent update


2026-01-15 16:33:37,290 2391938 DEBUG tecnibo170 odoo.addons.queue_job.controllers.main: <Job d665ad65-1df5-4679-8d59-dd33c41f9d72, priority:10> postponed 

2026-01-15 16:33:37,291 2391941 DEBUG ? odoo.addons.queue_job.jobrunner.channels: job d665ad65-1df5-4679-8d59-dd33c41f9d72 properties changed, rescheduling it 

2026-01-15 16:33:37,291 2391941 DEBUG ? odoo.addons.queue_job.jobrunner.channels: job d665ad65-1df5-4679-8d59-dd33c41f9d72 marked pending in channel root.heavy(C:∞,Q:1,R:0,F:2) ```

resolved it using this code: queue_job/jobrunner/runnuer.py

    def _query_requeue_dead_jobs(self):
        return """
            UPDATE
                queue_job
            SET
                state=(
                    CASE
                        WHEN
                            max_retries IS NOT NULL AND
                            max_retries != 0 AND -- infinite retries if max_retries is 0
                            retry IS NOT NULL AND
                            retry>max_retries
                        THEN 'failed'
                        ELSE 'pending'
                    END),
                retry=(
                    CASE
                        WHEN state='started'
                        THEN COALESCE(retry,0)+1 ELSE retry
                    END),
                exc_name=(
                    CASE
                        WHEN
                            max_retries IS NOT NULL AND
                            max_retries != 0 AND -- infinite retries if max_retries is 0
                            retry IS NOT NULL AND
                            retry>max_retries
                        THEN 'JobFoundDead'
                        ELSE exc_name
                    END),
                exc_info=(
                    CASE
                        WHEN
                            max_retries IS NOT NULL AND
                            max_retries != 0 AND -- infinite retries if max_retries is 0
                            retry IS NOT NULL AND
                            retry>max_retries
                        THEN 'Job found dead after too many retries'
                        ELSE exc_info
                    END)
            WHERE
                id in (
                    SELECT
                        queue_job_id
                    FROM
                        queue_job_lock
                    WHERE
                        queue_job_id in (
                            SELECT
                                id
                            FROM
                                queue_job
                            WHERE
                                state = 'enqueued' -- CHANGED FROM IN ('enqueued', 'started')
                                AND date_enqueued <
                                (now() AT TIME ZONE 'utc' - INTERVAL '10 sec')
                        )
                    FOR UPDATE SKIP LOCKED
                )
            RETURNING uuid
            """```

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions