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):