|
7 | 7 | from datetime import datetime
|
8 | 8 | from io import StringIO
|
9 | 9 |
|
| 10 | +import psutil |
10 | 11 | from psycopg2 import OperationalError
|
11 | 12 |
|
12 | 13 | from odoo import _, api, fields, models, tools
|
@@ -161,6 +162,7 @@ def _process(self, commit=False):
|
161 | 162 | @api.model
|
162 | 163 | def _job_runner(self, commit=True):
|
163 | 164 | """Short-lived job runner, triggered by async crons"""
|
| 165 | + self._release_started_jobs(commit=commit) |
164 | 166 | job = self._acquire_one_job(commit=commit)
|
165 | 167 | while job:
|
166 | 168 | job._process(commit=commit)
|
@@ -214,6 +216,24 @@ def _ensure_cron_trigger(self):
|
214 | 216 | if delayed_etas:
|
215 | 217 | self._cron_trigger(at=list(delayed_etas))
|
216 | 218 |
|
| 219 | + @api.model |
| 220 | + def _release_started_jobs(self, commit=False): |
| 221 | + pids = [x.pid for x in psutil.process_iter()] |
| 222 | + for record in self.search( |
| 223 | + [("state", "=", "started"), ("worker_pid", "not in", pids)] |
| 224 | + ): |
| 225 | + job = Job._load_from_db_record(record) |
| 226 | + job.set_pending() |
| 227 | + job.store() |
| 228 | + _logger.info( |
| 229 | + "release started job %s[channel=%s,uuid=%s]", |
| 230 | + record.id, |
| 231 | + record.channel, |
| 232 | + record.uuid, |
| 233 | + ) |
| 234 | + if commit: # pragma: no cover |
| 235 | + self.env.cr.commit() # pylint: disable=invalid-commit |
| 236 | + |
217 | 237 | @api.model_create_multi
|
218 | 238 | def create(self, vals_list):
|
219 | 239 | # When jobs are created, also create the cron trigger
|
|
0 commit comments