Skip to content

Commit 1c94494

Browse files
committed
[IMP] queue_job_cron_jobrunner: avoid to loop until the end of queue job list
wait the next cron trigger instead to avoid to reach the limit_time_real_cron limit.
1 parent c51f4b4 commit 1c94494

File tree

5 files changed

+67
-39
lines changed

5 files changed

+67
-39
lines changed

queue_job_cron_jobrunner/README.rst

-7
Original file line numberDiff line numberDiff line change
@@ -78,13 +78,6 @@ Parallel execution of jobs can be achieved by leveraging multiple ``ir.cron`` re
7878
* Duplicate the ``queue_job_cron`` cron record as many times as needed, until you have
7979
as much records as cron workers.
8080

81-
Known issues / Roadmap
82-
======================
83-
84-
* Support channel capacity and priority. (See ``_acquire_one_job``)
85-
* Gracefully handle CronWorker CPU timeouts. (See ``_job_runner``)
86-
* Commit transaction after job state updated to started. (See ``_process``)
87-
8881
Bug Tracker
8982
===========
9083

queue_job_cron_jobrunner/models/queue_job.py

+37-9
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
import logging
66
import traceback
7-
from datetime import datetime
7+
from datetime import datetime, timedelta
88
from io import StringIO
99

1010
import psutil
@@ -164,17 +164,45 @@ def _job_runner(self, commit=True):
164164
"""Short-lived job runner, triggered by async crons"""
165165
self._release_started_jobs(commit=commit)
166166
job = self._acquire_one_job(commit=commit)
167+
167168
while job:
168169
job._process(commit=commit)
170+
171+
if self._stop_processing():
172+
_logger.info(
173+
"Stop processing queue jobs in this "
174+
"ir.cron call, waiting next ir.cron call.",
175+
)
176+
return
177+
169178
job = self._acquire_one_job(commit=commit)
170-
# TODO: If limit_time_real_cron is reached before all the jobs are done,
171-
# the worker will be killed abruptly.
172-
# Ideally, find a way to know if we're close to reaching this limit,
173-
# stop processing, and trigger a new execution to continue.
174-
#
175-
# if job and limit_time_real_cron_reached_or_about_to_reach:
176-
# self._cron_trigger()
177-
# break
179+
180+
@api.model
181+
def _stop_processing(self):
182+
# If a queue_job_runner cron nextcall is already passed
183+
# or in less than 5 seconds we stop processing queue job
184+
# here to avoid to reach the limit_time_real_cron limit
185+
next_cron_job_runner_trigger = (
186+
self.env["ir.cron"]
187+
.sudo()
188+
.search(
189+
[("queue_job_runner", "=", True)],
190+
limit=1,
191+
order="nextcall",
192+
)
193+
)
194+
stop_processing_threshold_seconds = int(
195+
self.env["ir.config_parameter"]
196+
.sudo()
197+
.get_param(
198+
"queue_job_cron_jobrunner.stop_processing_threshold_seconds", "5"
199+
)
200+
)
201+
if next_cron_job_runner_trigger.nextcall <= (
202+
fields.Datetime.now() + timedelta(seconds=stop_processing_threshold_seconds)
203+
):
204+
return True
205+
return False
178206

179207
@api.model
180208
def _cron_trigger(self, at=None):

queue_job_cron_jobrunner/readme/ROADMAP.rst

-3
This file was deleted.

queue_job_cron_jobrunner/static/description/index.html

+10-19
Original file line numberDiff line numberDiff line change
@@ -392,12 +392,11 @@ <h1 class="title">Queue Job Cron Jobrunner</h1>
392392
<div class="contents local topic" id="contents">
393393
<ul class="simple">
394394
<li><a class="reference internal" href="#configuration" id="toc-entry-1">Configuration</a></li>
395-
<li><a class="reference internal" href="#known-issues-roadmap" id="toc-entry-2">Known issues / Roadmap</a></li>
396-
<li><a class="reference internal" href="#bug-tracker" id="toc-entry-3">Bug Tracker</a></li>
397-
<li><a class="reference internal" href="#credits" id="toc-entry-4">Credits</a><ul>
398-
<li><a class="reference internal" href="#authors" id="toc-entry-5">Authors</a></li>
399-
<li><a class="reference internal" href="#contributors" id="toc-entry-6">Contributors</a></li>
400-
<li><a class="reference internal" href="#maintainers" id="toc-entry-7">Maintainers</a></li>
395+
<li><a class="reference internal" href="#bug-tracker" id="toc-entry-2">Bug Tracker</a></li>
396+
<li><a class="reference internal" href="#credits" id="toc-entry-3">Credits</a><ul>
397+
<li><a class="reference internal" href="#authors" id="toc-entry-4">Authors</a></li>
398+
<li><a class="reference internal" href="#contributors" id="toc-entry-5">Contributors</a></li>
399+
<li><a class="reference internal" href="#maintainers" id="toc-entry-6">Maintainers</a></li>
401400
</ul>
402401
</li>
403402
</ul>
@@ -423,32 +422,24 @@ <h1><a class="toc-backref" href="#toc-entry-1">Configuration</a></h1>
423422
as much records as cron workers.</li>
424423
</ul>
425424
</div>
426-
<div class="section" id="known-issues-roadmap">
427-
<h1><a class="toc-backref" href="#toc-entry-2">Known issues / Roadmap</a></h1>
428-
<ul class="simple">
429-
<li>Support channel capacity and priority. (See <tt class="docutils literal">_acquire_one_job</tt>)</li>
430-
<li>Gracefully handle CronWorker CPU timeouts. (See <tt class="docutils literal">_job_runner</tt>)</li>
431-
<li>Commit transaction after job state updated to started. (See <tt class="docutils literal">_process</tt>)</li>
432-
</ul>
433-
</div>
434425
<div class="section" id="bug-tracker">
435-
<h1><a class="toc-backref" href="#toc-entry-3">Bug Tracker</a></h1>
426+
<h1><a class="toc-backref" href="#toc-entry-2">Bug Tracker</a></h1>
436427
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/queue/issues">GitHub Issues</a>.
437428
In case of trouble, please check there if your issue has already been reported.
438429
If you spotted it first, help us to smash it by providing a detailed and welcomed
439430
<a class="reference external" href="https://github.com/OCA/queue/issues/new?body=module:%20queue_job_cron_jobrunner%0Aversion:%2014.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
440431
<p>Do not contact contributors directly about support or help with technical issues.</p>
441432
</div>
442433
<div class="section" id="credits">
443-
<h1><a class="toc-backref" href="#toc-entry-4">Credits</a></h1>
434+
<h1><a class="toc-backref" href="#toc-entry-3">Credits</a></h1>
444435
<div class="section" id="authors">
445-
<h2><a class="toc-backref" href="#toc-entry-5">Authors</a></h2>
436+
<h2><a class="toc-backref" href="#toc-entry-4">Authors</a></h2>
446437
<ul class="simple">
447438
<li>Camptocamp SA</li>
448439
</ul>
449440
</div>
450441
<div class="section" id="contributors">
451-
<h2><a class="toc-backref" href="#toc-entry-6">Contributors</a></h2>
442+
<h2><a class="toc-backref" href="#toc-entry-5">Contributors</a></h2>
452443
<ul>
453444
<li><p class="first"><a class="reference external" href="https://www.camptocamp.com">Camptocamp</a></p>
454445
<blockquote>
@@ -460,7 +451,7 @@ <h2><a class="toc-backref" href="#toc-entry-6">Contributors</a></h2>
460451
</ul>
461452
</div>
462453
<div class="section" id="maintainers">
463-
<h2><a class="toc-backref" href="#toc-entry-7">Maintainers</a></h2>
454+
<h2><a class="toc-backref" href="#toc-entry-6">Maintainers</a></h2>
464455
<p>This module is maintained by the OCA.</p>
465456
<a class="reference external image-reference" href="https://odoo-community.org">
466457
<img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" />

queue_job_cron_jobrunner/tests/test_queue_job.py

+20-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# @author Iván Todorovich <[email protected]>
33
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
44

5-
from datetime import datetime
5+
from datetime import datetime, timedelta
66
from unittest import mock
77

88
from freezegun import freeze_time
@@ -37,12 +37,30 @@ def test_queue_job_process(self):
3737
job3 = self.env["res.partner"].with_delay(eta=3600).create({"name": "Test"})
3838
job3_record = job3.db_record()
3939
# Run the job processing cron
40+
self.cron.nextcall = datetime.now() + timedelta(seconds=600)
4041
self.env["queue.job"]._job_runner(commit=False)
4142
# Check that the jobs were processed
4243
self.assertEqual(job1_record.state, "done", "Processed OK")
4344
self.assertEqual(job2_record.state, "failed", "Has errors")
4445
self.assertEqual(job3_record.state, "pending", "Still pending, because of eta")
4546

47+
def test_stop_processing_job(self):
48+
self.cron.nextcall = datetime(2022, 2, 22, 22, 22, 22)
49+
self.env["ir.config_parameter"].set_param(
50+
"queue_job_cron_jobrunner.stop_processing_threshold_seconds", "60"
51+
)
52+
job1 = self.env["res.partner"].with_delay().create({"name": "test"})
53+
job1_record = job1.db_record()
54+
job2 = self.env["res.partner"].with_delay().create({"name": "Test"})
55+
job2_record = job2.db_record()
56+
with freeze_time("2022-02-22 22:21:23"):
57+
# Run the job processing cron, fist job is taken anyway
58+
# second job depends if next call is soon here in 59s
59+
# so stop starting new job waiting for the next cron thread
60+
self.env["queue.job"]._job_runner(commit=False)
61+
self.assertEqual(job1_record.state, "done", "Processed OK")
62+
self.assertEqual(job2_record.state, "pending", "no time left to start it")
63+
4664
@freeze_time("2022-02-22 22:22:22")
4765
def test_queue_job_cron_trigger_enqueue_dependencies(self):
4866
"""Test that ir.cron execution enqueue waiting dependencies"""
@@ -53,6 +71,7 @@ def test_queue_job_cron_trigger_enqueue_dependencies(self):
5371
job_record = delayable._generated_job.db_record()
5472
job_record_depends = delayable2._generated_job.db_record()
5573

74+
self.cron.nextcall = datetime(2022, 2, 22, 23, 23, 23)
5675
self.env["queue.job"]._job_runner(commit=False)
5776

5877
self.assertEqual(job_record.state, "done", "Processed OK")

0 commit comments

Comments
 (0)