-
-
Notifications
You must be signed in to change notification settings - Fork 536
[13.0] Deprecate job decorators #274
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
44cca3d
27208af
59e3eaf
97bfbf4
27687b2
4cd3ada
8432350
b371414
509af75
007922f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| <odoo noupdate="1"> | ||
| <record id="job_function_base_import_import_split_file" model="queue.job.function"> | ||
| <field name="model_id" ref="base_import.model_base_import_import" /> | ||
| <field name="method">_split_file</field> | ||
| <field | ||
| name="related_action" | ||
| eval='{"func_name": "_related_action_attachment"}' | ||
| /> | ||
| </record> | ||
| <record | ||
| id="job_function_base_import_import_import_one_chunk" | ||
| model="queue.job.function" | ||
| > | ||
| <field name="model_id" ref="base_import.model_base_import_import" /> | ||
| <field name="method">_import_one_chunk</field> | ||
| <field | ||
| name="related_action" | ||
| eval='{"func_name": "_related_action_attachment"}' | ||
| /> | ||
| </record> | ||
| </odoo> | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| <odoo noupdate="1"> | ||
| <record id="job_function_queue_job__test_job" model="queue.job.function"> | ||
| <field name="model_id" ref="queue_job.model_queue_job" /> | ||
| <field name="method">_test_job</field> | ||
| </record> | ||
| </odoo> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,4 @@ | ||
| # Copyright 2013-2016 Camptocamp | ||
| # Copyright 2013-2020 Camptocamp | ||
| # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html) | ||
|
|
||
| import functools | ||
|
|
@@ -42,9 +42,6 @@ class DelayableRecordset(object): | |
| delayable = DelayableRecordset(recordset, priority=20) | ||
| delayable.method(args, kwargs) | ||
|
|
||
| ``method`` must be a method of the recordset's Model, decorated with | ||
| :func:`~odoo.addons.queue_job.job.job`. | ||
|
|
||
| The method call will be processed asynchronously in the job queue, with | ||
| the passed arguments. | ||
|
|
||
|
|
@@ -78,12 +75,6 @@ def __getattr__(self, name): | |
| ) | ||
| ) | ||
| recordset_method = getattr(self.recordset, name) | ||
| if not getattr(recordset_method, "delayable", None): | ||
| raise AttributeError( | ||
| "method %s on %s is not allowed to be delayed, " | ||
| "it should be decorated with odoo.addons.queue_job.job.job" | ||
| % (name, self.recordset) | ||
| ) | ||
|
|
||
| def delay(*args, **kwargs): | ||
| return Job.enqueue( | ||
|
|
@@ -453,6 +444,16 @@ def __init__( | |
| self.job_model = self.env["queue.job"] | ||
| self.job_model_name = "queue.job" | ||
|
|
||
| self.job_config = ( | ||
| self.env["queue.job.function"] | ||
| .sudo() | ||
| .job_config( | ||
| self.env["queue.job.function"].job_function_name( | ||
| self.model_name, self.method_name | ||
| ) | ||
| ) | ||
| ) | ||
|
|
||
| self.state = PENDING | ||
|
|
||
| self.retry = 0 | ||
|
|
@@ -554,9 +555,14 @@ def store(self): | |
| if self.identity_key: | ||
| vals["identity_key"] = self.identity_key | ||
|
|
||
| job_model = self.env["queue.job"] | ||
| # The sentinel is used to prevent edition sensitive fields (such as | ||
| # method_name) from RPC methods. | ||
| edit_sentinel = job_model.EDIT_SENTINEL | ||
|
|
||
| db_record = self.db_record() | ||
| if db_record: | ||
| db_record.write(vals) | ||
| db_record.with_context(_job_edit_sentinel=edit_sentinel).write(vals) | ||
| else: | ||
| date_created = self.date_created | ||
| # The following values must never be modified after the | ||
|
|
@@ -578,7 +584,7 @@ def store(self): | |
| if self.channel: | ||
| vals.update({"channel": self.channel}) | ||
|
|
||
| self.env[self.job_model_name].sudo().create(vals) | ||
| job_model.with_context(_job_edit_sentinel=edit_sentinel).sudo().create(vals) | ||
|
|
||
| def db_record(self): | ||
| return self.db_record_from_uuid(self.env, self.uuid) | ||
|
|
@@ -672,7 +678,10 @@ def __repr__(self): | |
| return "<Job %s, priority:%d>" % (self.uuid, self.priority) | ||
|
|
||
| def _get_retry_seconds(self, seconds=None): | ||
| retry_pattern = self.func.retry_pattern | ||
| retry_pattern = self.job_config.retry_pattern | ||
| if not retry_pattern: | ||
| # TODO deprecated by :job-no-decorator: | ||
| retry_pattern = getattr(self.func, "retry_pattern", None) | ||
| if not seconds and retry_pattern: | ||
| # ordered from higher to lower count of retries | ||
| patt = sorted(retry_pattern.items(), key=lambda t: t[0]) | ||
|
|
@@ -701,20 +710,29 @@ def postpone(self, result=None, seconds=None): | |
|
|
||
| def related_action(self): | ||
| record = self.db_record() | ||
| if hasattr(self.func, "related_action"): | ||
| if not self.job_config.related_action_enable: | ||
| return None | ||
|
|
||
| funcname = self.job_config.related_action_func_name | ||
| if not funcname and hasattr(self.func, "related_action"): | ||
| # TODO deprecated by :job-no-decorator: | ||
| funcname = self.func.related_action | ||
| # decorator is set but empty: disable the default one | ||
| if not funcname: | ||
| return None | ||
| else: | ||
|
|
||
| if not funcname: | ||
| funcname = record._default_related_action | ||
| if not isinstance(funcname, str): | ||
| raise ValueError( | ||
| "related_action must be the name of the " | ||
| "method on queue.job as string" | ||
| ) | ||
| action = getattr(record, funcname) | ||
| action_kwargs = getattr(self.func, "kwargs", {}) | ||
| action_kwargs = self.job_config.related_action_kwargs | ||
| if not action_kwargs: | ||
| # TODO deprecated by :job-no-decorator: | ||
| action_kwargs = getattr(self.func, "kwargs", {}) | ||
| return action(**action_kwargs) | ||
|
|
||
|
|
||
|
|
@@ -724,9 +742,13 @@ def _is_model_method(func): | |
| ) | ||
|
|
||
|
|
||
| # TODO deprecated by :job-no-decorator: | ||
| def job(func=None, default_channel="root", retry_pattern=None): | ||
| """Decorator for job methods. | ||
|
|
||
| Deprecated. Use ``queue.job.function`` XML records (details in | ||
| ``readme/USAGE.rst``). | ||
|
|
||
| It enables the possibility to use a Model's method as a job function. | ||
|
|
||
| Optional argument: | ||
|
|
@@ -810,6 +832,25 @@ def retryable_example(): | |
| job, default_channel=default_channel, retry_pattern=retry_pattern | ||
| ) | ||
|
|
||
| xml_fields = [ | ||
| ' <field name="model_id" ref="[insert model xmlid]" />\n' | ||
| ' <field name="method">_test_job</field>\n' | ||
| ] | ||
| if default_channel: | ||
| xml_fields.append(' <field name="channel_id" ref="[insert channel xmlid]"/>') | ||
| if retry_pattern: | ||
| xml_fields.append(' <field name="retry_pattern">{retry_pattern}</field>') | ||
|
|
||
| xml_record = ( | ||
| '<record id="job_function_[insert model]_{method}"' | ||
| ' model="queue.job.function">\n' + "\n".join(xml_fields) + "\n</record>" | ||
| ).format(**{"method": func.__name__, "retry_pattern": retry_pattern}) | ||
| _logger.warning( | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @guewen IMHO this is too much as it will break all runbot builds in repos that use queues. See https://runbot.odoo-community.org/runbot/build/3450323 for example. Is it wanted ? Or maybe this can go into INFO.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You are right, I didn't realize runbot would not agree. We should move it to info, and move the XML snippet to debug because it is too verbose at the moment. I'll try to open a PR tomorrow. |
||
| "@job is deprecated and no longer needed, if you need custom options, " | ||
| "use an XML record:\n%s", | ||
| xml_record, | ||
| ) | ||
|
|
||
| def delay_from_model(*args, **kwargs): | ||
| raise AttributeError( | ||
| "method.delay() can no longer be used, the general form is " | ||
|
|
@@ -832,9 +873,13 @@ def delay_from_model(*args, **kwargs): | |
| return func | ||
|
|
||
|
|
||
| # TODO deprecated by :job-no-decorator: | ||
| def related_action(action=None, **kwargs): | ||
| """Attach a *Related Action* to a job (decorator) | ||
|
|
||
| Deprecated. Use ``queue.job.function`` XML records (details in | ||
| ``readme/USAGE.rst``). | ||
|
|
||
| A *Related Action* will appear as a button on the Odoo view. | ||
| The button will execute the action, usually it will open the | ||
| form view of the record related to the job. | ||
|
|
@@ -894,6 +939,29 @@ def export_product(self): | |
| """ | ||
|
|
||
| def decorate(func): | ||
| related_action_dict = { | ||
| "func_name": action, | ||
| } | ||
| if kwargs: | ||
| related_action_dict["kwargs"] = kwargs | ||
|
|
||
| xml_fields = ( | ||
| ' <field name="model_id" ref="[insert model xmlid]" />\n' | ||
| ' <field name="method">_test_job</field>\n' | ||
| ' <field name="related_action">{related_action}</field>' | ||
| ) | ||
|
|
||
| xml_record = ( | ||
| '<record id="job_function_[insert model]_{method}"' | ||
| ' model="queue.job.function">\n' + xml_fields + "\n</record>" | ||
| ).format(**{"method": func.__name__, "related_action": action}) | ||
| _logger.warning( | ||
| "@related_action is deprecated and no longer needed," | ||
| " add these options in a 'queue.job.function'" | ||
| " XML record:\n%s", | ||
| xml_record, | ||
| ) | ||
|
|
||
| func.related_action = action | ||
| func.kwargs = kwargs | ||
| return func | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html) | ||
|
|
||
| import logging | ||
|
|
||
| from odoo import SUPERUSER_ID, api, exceptions | ||
|
|
||
| _logger = logging.getLogger(__name__) | ||
|
|
||
|
|
||
| def migrate(cr, version): | ||
| with api.Environment.manage(): | ||
| env = api.Environment(cr, SUPERUSER_ID, {}) | ||
| for job_func in env["queue.job.function"].search([]): | ||
| try: | ||
| # trigger inverse field to set model_id and method | ||
| job_func.name = job_func.name | ||
| except exceptions.UserError: | ||
| # ignore invalid entries not to block migration | ||
| _logger.error( | ||
| "could not migrate job function '%s' (id: %s), invalid name", | ||
| job_func.name, | ||
| job_func.id, | ||
| ) |
Uh oh!
There was an error while loading. Please reload this page.