Skip to content
This repository has been archived by the owner on Feb 22, 2024. It is now read-only.

Flask context inside of delayed job. #3

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 3 additions & 1 deletion AUTHORS
Expand Up @@ -9,4 +9,6 @@ Development Lead
Patches and Suggestions
```````````````````````

- Jean-Philippe Serafin <https://github.com/jeanphix>
- Jean-Philippe Serafin <https://github.com/jeanphix>
- Mikhail Kashkin <https://github.com/xen>

8 changes: 8 additions & 0 deletions CHANGES
Expand Up @@ -3,6 +3,14 @@ Flask-RQ Changelog

Here you can see the full list of changes between each Flask-RQ release.

Version 0.3
-----------

Released August 14 2013

- Added `ctx_delay` method. Allow to work inside of flask context in delayed job


Version 0.2
-----------

Expand Down
36 changes: 36 additions & 0 deletions README.rst
Expand Up @@ -69,6 +69,42 @@ A specific queue name can also be passed as argument:

process.delay(2)

Sometimes you need to access application configuration context in your job.
There is special way to be able to work inside of context. Please note this is
not the same context. This is new, specially created context with the same
configuration, but without blueprints or extensions that you probably expect.
For example after long task you want to send email with result report:

.. code-block:: python

@job()
def context_process():

# Long stuff to process

from flask import current_app
from flask.ext.mail import Mail, Message
mail = Mail()
# current_app.config is almost the same as in Flask application
# that call your code
mail.init_app(current_app)
msg = Message("Report",
sender="from@example.com",
recipients=["to@example.com"])
mail.send(msg)


# inside of your view

@app.route('/make_long_report')
def report(project_id):
context_process.ctx_delay()
return 'Check your inbox in few minutes!'


If you need to differentiate contexts then name of Flask application inside of
worker job is `worker`.


``get_queue`` function
~~~~~~~~~~~~~~~~~~~~~~
Expand Down
23 changes: 22 additions & 1 deletion flask_rq.py
Expand Up @@ -14,7 +14,7 @@

import redis

from flask import current_app
from flask import current_app, Flask
from redis._compat import urlparse
from rq import Queue, Worker

Expand Down Expand Up @@ -73,6 +73,21 @@ def get_worker(*queues):
connection=get_connection(queues[0]))


class Cfg:
# Flask doesn't know how to read config from dictionary
# so we need to create "class-like" config
def __init__(self, **entries):
self.__dict__.update(entries)


def ctx_run(fn, cfg, *args, **kwargs):
# call wrapper that create Flask context with stored config dict
app = Flask('worker')
app.config.from_object(cfg)
with app.app_context():
fn(*args, **kwargs)


def job(func_or_queue=None):
if callable(func_or_queue):
func = func_or_queue
Expand All @@ -86,7 +101,13 @@ def delay(*args, **kwargs):
q = get_queue(queue)
return q.enqueue(fn, *args, **kwargs)

def ctx_delay(*args, **kwargs):
q = get_queue(queue)
cfg = Cfg(**dict(current_app.config))
return q.enqueue(ctx_run, fn, cfg, *args, **kwargs)

fn.delay = delay
fn.ctx_delay = ctx_delay
return fn

if func is not None:
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Expand Up @@ -19,7 +19,7 @@

setup(
name='Flask-RQ',
version='0.2',
version='0.3',
url='http://packages.python.org/Flask-RQ/',
license='MIT',
author='Matthew Wright',
Expand Down
5 changes: 5 additions & 0 deletions tests/flaskrq_tests.py
Expand Up @@ -53,6 +53,11 @@ def test_job_default(self):
self.assertEqual(len(get_queue().jobs), 1)
get_worker().work(True)

def test_ctx_job(self):
simple.ctx_delay(0)
self.assertEqual(len(get_queue().jobs), 1)
get_worker().work(True)

def test_job_specified_queue(self):
specified.delay(3)
self.assertEqual(len(get_queue('low').jobs), 1)
Expand Down
6 changes: 6 additions & 0 deletions tests/jobs.py
Expand Up @@ -13,3 +13,9 @@ def simple(i):
def specified(i):
time.sleep(5)
return i

@job
def simple_ctx():
from flask import current_app
time.sleep(5)
return current_app.name