mirror of
https://github.com/django-q2/django-q2.git
synced 2026-10-06 13:28:13 +08:00
Post execute signal and tests (#580)
* adds post_execute signal and tests * Updates signal docts * Fixes typo in docs
This commit is contained in:
+4
-2
@@ -43,7 +43,7 @@ from django_q.conf import (
|
|||||||
from django_q.humanhash import humanize
|
from django_q.humanhash import humanize
|
||||||
from django_q.models import Schedule, Success, Task
|
from django_q.models import Schedule, Success, Task
|
||||||
from django_q.queues import Queue
|
from django_q.queues import Queue
|
||||||
from django_q.signals import pre_execute
|
from django_q.signals import post_execute, pre_execute
|
||||||
from django_q.signing import BadSignature, SignedPackage
|
from django_q.signing import BadSignature, SignedPackage
|
||||||
from django_q.status import Stat, Status
|
from django_q.status import Stat, Status
|
||||||
|
|
||||||
@@ -386,6 +386,8 @@ def monitor(result_queue: Queue, broker: Broker = None):
|
|||||||
ack_id = task.pop("ack_id", False)
|
ack_id = task.pop("ack_id", False)
|
||||||
if ack_id and (task["success"] or task.get("ack_failure", False)):
|
if ack_id and (task["success"] or task.get("ack_failure", False)):
|
||||||
broker.acknowledge(ack_id)
|
broker.acknowledge(ack_id)
|
||||||
|
# signal execution done
|
||||||
|
post_execute.send(sender="django_q", task=task)
|
||||||
# log the result
|
# log the result
|
||||||
if task["success"]:
|
if task["success"]:
|
||||||
# log success
|
# log success
|
||||||
@@ -745,7 +747,7 @@ def rss_check():
|
|||||||
|
|
||||||
|
|
||||||
def localtime() -> datetime:
|
def localtime() -> datetime:
|
||||||
""" Override for timezone.localtime to deal with naive times and local times"""
|
"""Override for timezone.localtime to deal with naive times and local times"""
|
||||||
if settings.USE_TZ:
|
if settings.USE_TZ:
|
||||||
return timezone.localtime()
|
return timezone.localtime()
|
||||||
return datetime.now()
|
return datetime.now()
|
||||||
|
|||||||
@@ -37,3 +37,6 @@ pre_enqueue = Signal()
|
|||||||
|
|
||||||
# args: func, task
|
# args: func, task
|
||||||
pre_execute = Signal()
|
pre_execute = Signal()
|
||||||
|
|
||||||
|
# args: task
|
||||||
|
post_execute = Signal()
|
||||||
|
|||||||
@@ -2,8 +2,10 @@ import os
|
|||||||
import sys
|
import sys
|
||||||
import threading
|
import threading
|
||||||
import uuid as uuidlib
|
import uuid as uuidlib
|
||||||
|
from math import copysign
|
||||||
from multiprocessing import Event, Value
|
from multiprocessing import Event, Value
|
||||||
from time import sleep
|
from time import sleep
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
@@ -17,6 +19,7 @@ from django_q.conf import Conf
|
|||||||
from django_q.humanhash import DEFAULT_WORDLIST, uuid
|
from django_q.humanhash import DEFAULT_WORDLIST, uuid
|
||||||
from django_q.models import Success, Task
|
from django_q.models import Success, Task
|
||||||
from django_q.queues import Queue
|
from django_q.queues import Queue
|
||||||
|
from django_q.signals import post_execute, pre_enqueue, pre_execute
|
||||||
from django_q.status import Stat
|
from django_q.status import Stat
|
||||||
from django_q.tasks import (
|
from django_q.tasks import (
|
||||||
async_task,
|
async_task,
|
||||||
@@ -609,6 +612,85 @@ def test_acknowledge_failure_override():
|
|||||||
assert broker.acknowledgements.get("test_success_ack_id") == 1
|
assert broker.acknowledgements.get("test_success_ack_id") == 1
|
||||||
|
|
||||||
|
|
||||||
|
class TestSignals:
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_pre_enqueue_signal(self, broker):
|
||||||
|
broker.list_key = "pre_enqueue_test:q"
|
||||||
|
broker.delete_queue()
|
||||||
|
self.signal_was_called: bool = False
|
||||||
|
self.task: Optional[dict] = None
|
||||||
|
|
||||||
|
def handler(sender, task, **kwargs):
|
||||||
|
self.signal_was_called = True
|
||||||
|
self.task = task
|
||||||
|
|
||||||
|
pre_enqueue.connect(handler)
|
||||||
|
task_id = async_task("math.copysign", 1, -1, broker=broker)
|
||||||
|
assert self.signal_was_called is True
|
||||||
|
assert self.task.get("id") == task_id
|
||||||
|
pre_enqueue.disconnect(handler)
|
||||||
|
broker.delete_queue()
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_pre_execute_signal(self, broker):
|
||||||
|
broker.list_key = "pre_execute_test:q"
|
||||||
|
broker.delete_queue()
|
||||||
|
self.signal_was_called: bool = False
|
||||||
|
self.task: Optional[dict] = None
|
||||||
|
self.func = None
|
||||||
|
|
||||||
|
def handler(sender, task, func, **kwargs):
|
||||||
|
self.signal_was_called = True
|
||||||
|
self.task = task
|
||||||
|
self.func = func
|
||||||
|
|
||||||
|
pre_execute.connect(handler)
|
||||||
|
task_id = async_task("math.copysign", 1, -1, broker=broker)
|
||||||
|
task_queue = Queue()
|
||||||
|
result_queue = Queue()
|
||||||
|
event = Event()
|
||||||
|
event.set()
|
||||||
|
pusher(task_queue, event, broker=broker)
|
||||||
|
task_queue.put("STOP")
|
||||||
|
worker(task_queue, result_queue, Value("f", -1))
|
||||||
|
result_queue.put("STOP")
|
||||||
|
monitor(result_queue, broker)
|
||||||
|
broker.delete_queue()
|
||||||
|
assert self.signal_was_called is True
|
||||||
|
assert self.task.get("id") == task_id
|
||||||
|
assert self.func == copysign
|
||||||
|
pre_execute.disconnect(handler)
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_post_execute_signal(self, broker):
|
||||||
|
broker.list_key = "post_execute_test:q"
|
||||||
|
broker.delete_queue()
|
||||||
|
self.signal_was_called: bool = False
|
||||||
|
self.task: Optional[dict] = None
|
||||||
|
self.func = None
|
||||||
|
|
||||||
|
def handler(sender, task, **kwargs):
|
||||||
|
self.signal_was_called = True
|
||||||
|
self.task = task
|
||||||
|
|
||||||
|
post_execute.connect(handler)
|
||||||
|
task_id = async_task("math.copysign", 1, -1, broker=broker)
|
||||||
|
task_queue = Queue()
|
||||||
|
result_queue = Queue()
|
||||||
|
event = Event()
|
||||||
|
event.set()
|
||||||
|
pusher(task_queue, event, broker=broker)
|
||||||
|
task_queue.put("STOP")
|
||||||
|
worker(task_queue, result_queue, Value("f", -1))
|
||||||
|
result_queue.put("STOP")
|
||||||
|
monitor(result_queue, broker)
|
||||||
|
broker.delete_queue()
|
||||||
|
assert self.signal_was_called is True
|
||||||
|
assert self.task.get("id") == task_id
|
||||||
|
assert self.task.get("result") == -1
|
||||||
|
post_execute.disconnect(handler)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def assert_result(task):
|
def assert_result(task):
|
||||||
assert task is not None
|
assert task is not None
|
||||||
|
|||||||
+16
-5
@@ -24,20 +24,31 @@ executed by a worker. This signal provides two arguments:
|
|||||||
with a function path, this argument will be the callable function
|
with a function path, this argument will be the callable function
|
||||||
nonetheless.
|
nonetheless.
|
||||||
|
|
||||||
|
After executing a task
|
||||||
|
""""""""""""""""""""""
|
||||||
|
The ``django_q.signals.post_execute`` signal is emitted after a task is
|
||||||
|
executed by a worker and processed by the monitor. It included the ``task`` dictionary with the result.
|
||||||
|
|
||||||
|
|
||||||
Subscribing to a signal
|
Subscribing to a signal
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
||||||
Connecting to a Django Q signal is done in the same manner as any other Django
|
Connecting to a Django Q signal is done the same as any other Django
|
||||||
signal::
|
signal::
|
||||||
|
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
from django_q.signals import pre_enqueue, pre_execute
|
from django_q.signals import pre_enqueue, pre_execute, post_execute
|
||||||
|
|
||||||
@receiver(pre_enqueue)
|
@receiver(pre_enqueue)
|
||||||
def my_pre_enqueue_callback(sender, task, **kwargs):
|
def my_pre_enqueue_callback(sender, task, **kwargs):
|
||||||
print("Task {} will be enqueued".format(task["name"]))
|
print(f"Task {task['name']} will be queued")
|
||||||
|
|
||||||
@receiver(pre_execute)
|
@receiver(pre_execute)
|
||||||
def my_pre_execute_callback(sender, func, task, **kwargs):
|
def my_pre_execute_callback(sender, func, task, **kwargs):
|
||||||
print("Task {} will be executed by calling {}".format(
|
print(f"Task {task['name']} will be executed by calling {func}")
|
||||||
task["name"], func))
|
|
||||||
|
@receiver(post_execute)
|
||||||
|
def my_post_execute_callback(sender, task, **kwargs):
|
||||||
|
print(f"Task {task['name']} was executed with result {task['result']}")
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user