mirror of
https://github.com/django-q2/django-q2.git
synced 2026-10-06 01:48:12 +08:00
docs: Added a report example
Also added a test based on the example.
This commit is contained in:
@@ -35,5 +35,9 @@ def get_task_name(task):
|
|||||||
return task.name
|
return task.name
|
||||||
|
|
||||||
|
|
||||||
|
def get_user_id(user):
|
||||||
|
return user.id
|
||||||
|
|
||||||
|
|
||||||
def result(obj):
|
def result(obj):
|
||||||
print('RESULT HOOK {} : {}'.format(obj.name, obj.result))
|
print('RESULT HOOK {} : {}'.format(obj.name, obj.result))
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import sys
|
import sys
|
||||||
import os
|
|
||||||
from multiprocessing import Queue, Event, Value
|
from multiprocessing import Queue, Event, Value
|
||||||
import threading
|
import threading
|
||||||
|
|
||||||
|
from django.contrib.auth.models import User
|
||||||
|
import os
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
myPath = os.path.dirname(os.path.abspath(__file__))
|
myPath = os.path.dirname(os.path.abspath(__file__))
|
||||||
@@ -32,11 +33,13 @@ def r():
|
|||||||
def test_redis_connection(r):
|
def test_redis_connection(r):
|
||||||
assert r.ping() is True
|
assert r.ping() is True
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_sync(r):
|
def test_sync(r):
|
||||||
task = async('django_q.tests.tasks.count_letters', DEFAULT_WORDLIST, redis=r, sync=True)
|
task = async('django_q.tests.tasks.count_letters', DEFAULT_WORDLIST, redis=r, sync=True)
|
||||||
assert result(task) == 1506
|
assert result(task) == 1506
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_cluster_initial(r):
|
def test_cluster_initial(r):
|
||||||
list_key = 'initial_test:q'
|
list_key = 'initial_test:q'
|
||||||
@@ -98,28 +101,30 @@ def test_cluster(r):
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_async(r):
|
def test_async(r, admin_user):
|
||||||
list_key = 'cluster_test:q'
|
list_key = 'cluster_test:q'
|
||||||
r.delete(list_key)
|
r.delete(list_key)
|
||||||
a = async('django_q.tests.tasks.count_letters', DEFAULT_WORDLIST, hook='django_q.tests.test_cluster.assert_result',
|
a = async('django_q.tests.tasks.count_letters', DEFAULT_WORDLIST, hook='django_q.tests.test_cluster.assert_result',
|
||||||
list_key=list_key)
|
list_key=list_key, redis=r)
|
||||||
b = async('django_q.tests.tasks.count_letters2', WordClass(), hook='django_q.tests.test_cluster.assert_result',
|
b = async('django_q.tests.tasks.count_letters2', WordClass(), hook='django_q.tests.test_cluster.assert_result',
|
||||||
list_key=list_key)
|
list_key=list_key, redis=r)
|
||||||
# unknown argument
|
# unknown argument
|
||||||
c = async('django_q.tests.tasks.count_letters', DEFAULT_WORDLIST, 'oneargumentoomany',
|
c = async('django_q.tests.tasks.count_letters', DEFAULT_WORDLIST, 'oneargumentoomany',
|
||||||
hook='django_q.tests.test_cluster.assert_bad_result', list_key=list_key)
|
hook='django_q.tests.test_cluster.assert_bad_result', list_key=list_key, redis=r)
|
||||||
# unknown function
|
# unknown function
|
||||||
d = async('django_q.tests.tasks.does_not_exist', WordClass(), hook='django_q.tests.test_cluster.assert_bad_result',
|
d = async('django_q.tests.tasks.does_not_exist', WordClass(), hook='django_q.tests.test_cluster.assert_bad_result',
|
||||||
list_key=list_key)
|
list_key=list_key, redis=r)
|
||||||
# function without result
|
# function without result
|
||||||
e = async('django_q.tests.tasks.countdown', 100000, list_key=list_key)
|
e = async('django_q.tests.tasks.countdown', 100000, list_key=list_key, redis=r)
|
||||||
# function as instance
|
# function as instance
|
||||||
f = async(multiply, 753, 2, hook=assert_result, list_key=list_key)
|
f = async(multiply, 753, 2, hook=assert_result, list_key=list_key, redis=r)
|
||||||
# model as argument
|
# model as argument
|
||||||
g = async('django_q.tests.tasks.get_task_name', Task(name='John'), list_key=list_key)
|
g = async('django_q.tests.tasks.get_task_name', Task(name='John'), list_key=list_key, redis=r)
|
||||||
# args and kwargs and broken hook
|
# args and kwargs and broken hook
|
||||||
h = async('django_q.tests.tasks.word_multiply', 2, word='django', hook='fail.me', list_key=list_key, redis=r)
|
h = async('django_q.tests.tasks.word_multiply', 2, word='django', hook='fail.me', list_key=list_key, redis=r)
|
||||||
# check if everything has a task name
|
# args unpickle test
|
||||||
|
j = async('django_q.tests.tasks.get_user_id', admin_user, list_key=list_key, redis=r)
|
||||||
|
# check if everything has a task id
|
||||||
assert isinstance(a, str)
|
assert isinstance(a, str)
|
||||||
assert isinstance(b, str)
|
assert isinstance(b, str)
|
||||||
assert isinstance(c, str)
|
assert isinstance(c, str)
|
||||||
@@ -128,8 +133,9 @@ def test_async(r):
|
|||||||
assert isinstance(f, str)
|
assert isinstance(f, str)
|
||||||
assert isinstance(g, str)
|
assert isinstance(g, str)
|
||||||
assert isinstance(h, str)
|
assert isinstance(h, str)
|
||||||
|
assert isinstance(j, str)
|
||||||
# run the cluster to execute the tasks
|
# run the cluster to execute the tasks
|
||||||
task_count = 8
|
task_count = 9
|
||||||
assert r.llen(list_key) == task_count
|
assert r.llen(list_key) == task_count
|
||||||
task_queue = Queue()
|
task_queue = Queue()
|
||||||
stop_event = Event()
|
stop_event = Event()
|
||||||
@@ -187,6 +193,11 @@ def test_async(r):
|
|||||||
assert result_h is not None
|
assert result_h is not None
|
||||||
assert result_h.success is True
|
assert result_h.success is True
|
||||||
assert result(h) == 12
|
assert result(h) == 12
|
||||||
|
# task j
|
||||||
|
result_j = fetch(j)
|
||||||
|
assert result_j is not None
|
||||||
|
assert result_j.success is True
|
||||||
|
assert result_j.result == result_j.args[0].id
|
||||||
r.delete(list_key)
|
r.delete(list_key)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+56
-5
@@ -1,10 +1,12 @@
|
|||||||
Examples
|
Examples
|
||||||
--------
|
--------
|
||||||
|
|
||||||
Async emails
|
Emails
|
||||||
============
|
======
|
||||||
|
|
||||||
Sending an email can take a while so why not queue it::
|
Sending an email can take a while so why not queue it:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
# Welcome mail with follow up example
|
# Welcome mail with follow up example
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
@@ -39,7 +41,9 @@ Since you're only telling Django Q to take care of the emails, you can quickly m
|
|||||||
Signals
|
Signals
|
||||||
=======
|
=======
|
||||||
|
|
||||||
A good place to use async tasks are Django's model signals. You don't want to delay the saving or creation of objects, but sometimes you want to trigger a lot of actions::
|
A good place to use async tasks are Django's model signals. You don't want to delay the saving or creation of objects, but sometimes you want to trigger a lot of actions:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
# Message on object change
|
# Message on object change
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
@@ -60,7 +64,9 @@ A good place to use async tasks are Django's model signals. You don't want to de
|
|||||||
# tell everyone
|
# tell everyone
|
||||||
async('tasks.inform_everyone', instance)
|
async('tasks.inform_everyone', instance)
|
||||||
|
|
||||||
The task will send a message to everyone else informing them that the users email address has changed. Note that this adds almost no overhead to the save action::
|
The task will send a message to everyone else informing them that the users email address has changed. Note that this adds almost no overhead to the save action:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
# tasks.py
|
# tasks.py
|
||||||
def inform_everyone(user):
|
def inform_everyone(user):
|
||||||
@@ -72,6 +78,7 @@ The task will send a message to everyone else informing them that the users emai
|
|||||||
'from@example.com', [u.email]))
|
'from@example.com', [u.email]))
|
||||||
return send_mass_mail(mails)
|
return send_mass_mail(mails)
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
# or do it async again
|
# or do it async again
|
||||||
def inform_everyone_async(user):
|
def inform_everyone_async(user):
|
||||||
@@ -82,8 +89,52 @@ The task will send a message to everyone else informing them that the users emai
|
|||||||
'New email', msg, 'from@example.com', [u.email])
|
'New email', msg, 'from@example.com', [u.email])
|
||||||
|
|
||||||
|
|
||||||
|
Of course you can do other things beside sending emails. These are just generic examples. You can use signals with async to update fields in other objects too.
|
||||||
|
Let's say this users email address is not just on the User object, but you stored it in some other places too without a reference.
|
||||||
|
By attaching an async action to the save signal, you can now update that email address in those other places without impacting the the time it takes to return your views.
|
||||||
|
|
||||||
|
|
||||||
|
Reports
|
||||||
|
=======
|
||||||
|
|
||||||
|
In this example the user requests a report and we let the cluster do the generating, while handling the result with a hook.
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
# Report generation with hook example
|
||||||
|
from django_q import async
|
||||||
|
|
||||||
|
# views.py
|
||||||
|
# user requests a report.
|
||||||
|
def create_report(request):
|
||||||
|
async('tasks.create_html_report',
|
||||||
|
request.user,
|
||||||
|
hook='tasks.email_report')
|
||||||
|
|
||||||
|
# tasks.py
|
||||||
|
# report generator
|
||||||
|
def create_html_report(user):
|
||||||
|
html_report = 'We had a great quarter!'
|
||||||
|
return html_report
|
||||||
|
|
||||||
|
# report mailer
|
||||||
|
def email_report(task):
|
||||||
|
if task.success:
|
||||||
|
# Email the report
|
||||||
|
async('django.core.mail.send_mail',
|
||||||
|
'The report you requested',
|
||||||
|
task.result,
|
||||||
|
'from@example.com',
|
||||||
|
task.args[0].email)
|
||||||
|
else:
|
||||||
|
# Tell the admins something went wrong
|
||||||
|
async('django.core.mail.mail_admins',
|
||||||
|
'Report generation failed',
|
||||||
|
task.result)
|
||||||
|
|
||||||
|
|
||||||
|
The hook is practical here, cause it allows us to detach the sending task from the report generation function and to report on possible failures.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
If you have an example you want to share, please submit a pull request on `github <https://github.com/Koed00/django-q/>`__.
|
If you have an example you want to share, please submit a pull request on `github <https://github.com/Koed00/django-q/>`__.
|
||||||
|
|||||||
Reference in New Issue
Block a user