Skip to content

Commit 8ec6ae7

Browse files
kittiuGuewen Baconnier
andcommitted
[13.0][IMP] queue_job, add decorator job_auto_delay
Co-authored-by: Guewen Baconnier <guewen.baconnier@camptocamp.com>
1 parent 3b49e06 commit 8ec6ae7

1 file changed

Lines changed: 72 additions & 0 deletions

File tree

queue_job/job.py

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -899,3 +899,75 @@ def decorate(func):
899899
return func
900900

901901
return decorate
902+
903+
904+
def job_auto_delay(func=None, default_channel="root", retry_pattern=None):
905+
"""Decorator to automatically delay as job method when called
906+
907+
The decorator applies ``odoo.addons.queue_job.job`` at the same time,
908+
so the decorated method is listed in job functions. The arguments
909+
are the same, propagated to the ``job`` decorator.
910+
911+
When a method is decorated by ``job_auto_delay``, any call to the method
912+
will not directly execute the method's body, but will instead enqueue a
913+
job.
914+
915+
The options of the job usually passed to ``with_delay()`` (priority,
916+
description, identity_key, ...) can be returned in a dictionary by a method
917+
named after the name of the method suffixed by ``_job_options`` which takes
918+
the same parameters as the initial method.
919+
920+
It is still possible to directly execute the method by setting a key
921+
``_job_force_sync`` to True in the environment context.
922+
923+
Example:
924+
925+
.. code-block:: python
926+
927+
class ProductProduct(models.Model):
928+
_inherit = 'product.product'
929+
930+
def foo_job_options(self, arg1):
931+
return {
932+
"priority": 100,
933+
"description": "Saying hello to {}".format(arg1)
934+
}
935+
936+
@job_auto_delay(default_channel="root.channel1")
937+
def foo(self, arg1):
938+
print("hello", arg1)
939+
940+
def button_x(self):
941+
foo("world")
942+
943+
The result when ``button_x`` is called, is that a new job for ``foo`` is
944+
delayed.
945+
946+
"""
947+
if func is None:
948+
return functools.partial(
949+
job_auto_delay, default_channel=default_channel, retry_pattern=retry_pattern
950+
)
951+
952+
def auto_delay(self, *args, **kwargs):
953+
if self.env.context.get("job_uuid") or self.env.context.get("_job_force_sync"):
954+
# we are in the job execution
955+
return func(self, *args, **kwargs)
956+
else:
957+
# replace the synchronous call by a job on itself
958+
method_name = func.__name__
959+
job_options_method = getattr(
960+
self, "{}_job_options".format(method_name), None
961+
)
962+
job_options = {}
963+
if job_options_method:
964+
job_options.update(job_options_method(*args, **kwargs))
965+
else:
966+
job_options = {}
967+
delayed = self.with_delay(**job_options)
968+
getattr(delayed, method_name)(*args, **kwargs)
969+
970+
return functools.update_wrapper(
971+
auto_delay,
972+
job(func, default_channel=default_channel, retry_pattern=retry_pattern),
973+
)

0 commit comments

Comments
 (0)