You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@allura.apache.org by br...@apache.org on 2025/12/10 16:52:36 UTC
(allura) 01/03: [#8592] prepend __task_ for special delay and flush_immediately task/event params. Add priority too
This is an automated email from the ASF dual-hosted git repository.
brondsem pushed a commit to branch db/8592
in repository https://gitbox.apache.org/repos/asf/allura.git
commit f9031d20beae4138efde38d273a3d66ea3c13b60
Author: Dave Brondsema <db...@slashdotmedia.com>
AuthorDate: Mon Dec 8 11:45:56 2025 -0500
[#8592] prepend __task_ for special delay and flush_immediately task/event params. Add priority too
---
Allura/allura/lib/app_globals.py | 20 +++++++++++++++++---
Allura/allura/lib/decorators.py | 24 +++++++++++++++++-------
Allura/allura/model/project.py | 6 +++---
Allura/allura/tests/test_decorators.py | 6 +++---
Allura/allura/tests/test_tasks.py | 4 ++--
ForgeTracker/forgetracker/model/ticket.py | 2 +-
6 files changed, 43 insertions(+), 19 deletions(-)
diff --git a/Allura/allura/lib/app_globals.py b/Allura/allura/lib/app_globals.py
index 33be87058..7f1e104f9 100644
--- a/Allura/allura/lib/app_globals.py
+++ b/Allura/allura/lib/app_globals.py
@@ -394,7 +394,21 @@ def get_timeline(self, *a, **kw):
return NullActivityStreamDirector()
def post_event(self, topic, *args, **kwargs):
- if 'flush_immediately' not in kwargs:
+ """
+ Creates an 'event' task. When it runs, it will call all matching @event_handler listeners.
+
+ :param topic: not used much, but passed through to listeners
+ :param args: not used much, but passed through to listeners
+ :param kwargs: not used much, but passed through to listeners
+ :param __task_delay: (optional) seconds to delay task execution (see MonQTask.post)
+ :param __task_priority: (optional) task priority (see MonQTask.post)
+ :return:
+ """
+ if 'flush_immediately' in kwargs and '__task_flush_immediately' not in kwargs:
+ # backwards compatibility
+ kwargs['__task_flush_immediately'] = kwargs.pop('flush_immediately')
+
+ if '__task_flush_immediately' not in kwargs:
try:
env = request.environ
except AttributeError:
@@ -402,12 +416,12 @@ def post_event(self, topic, *args, **kwargs):
else:
script_without_ming_middleware = env['PATH_INFO'] == '--script--'
if script_without_ming_middleware:
- kwargs['flush_immediately'] = True
+ kwargs['__task_flush_immediately'] = True
else:
# within tasks and web requests, ming middleware will flush everything to mongo
# so best to *not* flush immediately and let all db writes happen in order
# so there's no chance of an event being created and started while the initiating code is still running
- kwargs['flush_immediately'] = False
+ kwargs['__task_flush_immediately'] = False
allura.tasks.event_tasks.event.post(topic, *args, **kwargs)
@LazyProperty
diff --git a/Allura/allura/lib/decorators.py b/Allura/allura/lib/decorators.py
index cd27647b4..f6c578168 100644
--- a/Allura/allura/lib/decorators.py
+++ b/Allura/allura/lib/decorators.py
@@ -41,17 +41,21 @@
log = logging.getLogger(__name__)
-def task(*args, **kw):
+def task(*args, notifications_disabled=False):
"""Decorator that adds a ``.post()`` function to the decorated callable.
Calling ``<original_callable>.post(*args, **kw)`` queues the callable for
execution by a background worker process. All parameters must be
BSON-serializable.
+ ``<original_callable>.post()`` takes optional keyword arguments `__task_delay`, `__task_priority`, and
+ `__task_flush_immediately` which will be passed to :meth:`allura.model.monq_model.MonQTask.post` to control the
+ task.
+
Example usage::
@task
- def myfunc():
+ def myfunc(foo):
pass
@task(notifications_disabled=True)
@@ -59,17 +63,23 @@ def myotherfunc():
# No email notifications will be sent for c.project during this task
pass
+ myfunc.post(foo=bar, __task_delay=10)
+
"""
def task_(func):
def post(*args, **kwargs):
- delay = kwargs.pop('delay', 0)
- flush_immediately = kwargs.pop('flush_immediately', True)
+ # pass any __task_* kwargs to MonQTask.post instead of task function
+ task_kwargs = {}
+ for k, v in kwargs.copy().items():
+ if k.startswith('__task_'):
+ task_kwargs[k[7:]] = kwargs.pop(k)
+ if k in ('delay', 'flush_immediately'): # backwards compatibility for no __task_ prefix
+ task_kwargs[k] = kwargs.pop(k)
project = getattr(c, 'project', None)
- cm = (h.notifications_disabled if project and
- kw.get('notifications_disabled') else h.null_contextmanager)
+ cm = h.notifications_disabled if project and notifications_disabled else h.null_contextmanager
with cm(project):
from allura import model as M
- return M.MonQTask.post(func, args, kwargs, delay=delay, flush_immediately=flush_immediately)
+ return M.MonQTask.post(func, args, kwargs, **task_kwargs)
# if decorating a class, have to make it a staticmethod
# or it gets a spurious cls argument
func.post = staticmethod(post) if inspect.isclass(func) else post
diff --git a/Allura/allura/model/project.py b/Allura/allura/model/project.py
index 23726135c..815ca9cad 100644
--- a/Allura/allura/model/project.py
+++ b/Allura/allura/model/project.py
@@ -122,13 +122,13 @@ def subcategories(self):
class TroveCategoryMapperExtension(MapperExtension):
def after_insert(self, obj, state, sess):
- g.post_event('trove_category_created', obj.trove_cat_id, flush_immediately=True)
+ g.post_event('trove_category_created', obj.trove_cat_id, __task_flush_immediately=True)
def after_update(self, obj, state, sess):
- g.post_event('trove_category_updated', obj.trove_cat_id, flush_immediately=True)
+ g.post_event('trove_category_updated', obj.trove_cat_id, __task_flush_immediately=True)
def after_delete(self, obj, state, sess):
- g.post_event('trove_category_deleted', obj.trove_cat_id, flush_immediately=True)
+ g.post_event('trove_category_deleted', obj.trove_cat_id, __task_flush_immediately=True)
class TroveCategory(MappedClass):
diff --git a/Allura/allura/tests/test_decorators.py b/Allura/allura/tests/test_decorators.py
index 638f365d7..5b7ed112f 100644
--- a/Allura/allura/tests/test_decorators.py
+++ b/Allura/allura/tests/test_decorators.py
@@ -35,7 +35,7 @@ def func():
assert hasattr(func, 'post')
def test_with_params(self):
- @task(disable_notifications=True)
+ @task(notifications_disabled=True)
def func():
pass
assert hasattr(func, 'post')
@@ -43,7 +43,7 @@ def func():
@patch('allura.lib.decorators.c')
@patch('allura.model.MonQTask')
def test_post(self, c, MonQTask):
- @task(disable_notifications=True)
+ @task(notifications_disabled=True)
def func(s, foo=None, **kw):
pass
@@ -57,7 +57,7 @@ def mock_post(f, args, kw, delay=None):
c.project.notifications_disabled = False
MonQTask.post.side_effect = mock_post
- func.post('test', foo=2, delay=1)
+ func.post('test', foo=2, __task_delay=1)
class TestMemoize:
diff --git a/Allura/allura/tests/test_tasks.py b/Allura/allura/tests/test_tasks.py
index 95c24e9e3..5dfc88822 100644
--- a/Allura/allura/tests/test_tasks.py
+++ b/Allura/allura/tests/test_tasks.py
@@ -113,10 +113,10 @@ def test_fire_event(self):
assert self.called_with == [((1, 2), {'a': 5})], self.called_with
def test_post_event_explicit_flush(self):
- g.post_event('my_event1', flush_immediately=True)
+ g.post_event('my_event1', __task_flush_immediately=True)
assert M.MonQTask.query.get(task_name='allura.tasks.event_tasks.event', args=['my_event1'])
- g.post_event('my_event2', flush_immediately=False)
+ g.post_event('my_event2', __task_flush_immediately=False)
assert not M.MonQTask.query.get(task_name='allura.tasks.event_tasks.event', args=['my_event2'])
ThreadLocalODMSession.flush_all()
assert M.MonQTask.query.get(task_name='allura.tasks.event_tasks.event', args=['my_event2'])
diff --git a/ForgeTracker/forgetracker/model/ticket.py b/ForgeTracker/forgetracker/model/ticket.py
index 8445e63c6..b0cba01f1 100644
--- a/ForgeTracker/forgetracker/model/ticket.py
+++ b/ForgeTracker/forgetracker/model/ticket.py
@@ -261,7 +261,7 @@ def invalidate_bin_counts(self):
return
self._bin_counts_invalidated = datetime.utcnow()
from forgetracker import tasks # prevent circular import
- tasks.update_bin_counts.post(self.app_config_id, delay=delay)
+ tasks.update_bin_counts.post(self.app_config_id, __task_delay=delay)
def sortable_custom_fields_shown_in_search(self):
def solr_type(field_name):