Skip to content

Commit

Permalink
Re-adding django integration.
Browse files Browse the repository at this point in the history
  • Loading branch information
coleifer committed Jan 4, 2016
1 parent 2cb84f5 commit 1e28065
Show file tree
Hide file tree
Showing 14 changed files with 299 additions and 0 deletions.
12 changes: 12 additions & 0 deletions examples/django_ex/README
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
In one terminal, run:

./manage.py run_huey

In another terminal:

./manage.py shell

Commands to try out:

from test_app.commands import count_beans
res = count_beans(500)
Empty file.
17 changes: 17 additions & 0 deletions examples/django_ex/djangoex/settings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import logging

INSTALLED_APPS = [
'huey.contrib.djhuey',
'djangoex.test_app',
]

HUEY = {
'name': 'test-django',
'consumer': {
'loglevel': logging.DEBUG,
'workers': 2,
'scheduler_interval': 5,
},
}

SECRET_KEY = 'foo'
Empty file.
Empty file.
24 changes: 24 additions & 0 deletions examples/django_ex/djangoex/test_app/tasks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import random
from huey.contrib.djhuey import task, periodic_task, crontab, db_task


@task()
def count_beans(number):
print('-- counted %s beans --' % number)
return 'Counted %s beans' % number

@periodic_task(crontab(minute='*/5'))
def every_five_mins():
print('Every five minutes this will be printed by the consumer')

@task(retries=3, retry_delay=10)
def try_thrice():
if random.randint(1, 3) == 1:
print('OK')
else:
print('About to fail, will retry in 10 seconds')
raise Exception('Crap something went wrong')

@db_task()
def foo(number):
print('foo(%s)' % number)
4 changes: 4 additions & 0 deletions examples/django_ex/djangoex/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from django.conf.urls import patterns

urlpatterns = patterns('',
)
10 changes: 10 additions & 0 deletions examples/django_ex/manage.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/usr/bin/env python
import os
import sys

if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "djangoex.settings")

from django.core.management import execute_from_command_line

execute_from_command_line(sys.argv)
Empty file added huey/contrib/__init__.py
Empty file.
104 changes: 104 additions & 0 deletions huey/contrib/djhuey/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
from functools import wraps
import sys

from django.conf import settings
from django.db import connection

from huey import crontab
from huey import RedisHuey
from huey.utils import load_class


configuration_message = """
Configuring Huey for use with Django
====================================
Huey was designed to be simple to configure in the general case. For that
reason, huey will "just work" with no configuration at all provided you have
Redis installed and running locally.
On the other hand, you can configure huey manually using the following
setting structure.
The following example uses Redis on localhost, and will run four worker
processes:
HUEY = {
'name': 'my-app',
'connection': {'host': 'localhost', 'port': 6379},
'consumer': {
'workers': 4,
'worker_type': 'process', # "thread" or "greenlet" are other options
},
}
If you would like to configure Huey's logger using Django's integrated logging
settings, the logger used by consumer is named "huey.consumer".
Alternatively you can simply assign `settings.HUEY` to an actual `Huey`
object instance:
from huey import RedisHuey
HUEY = RedisHuey('my-app')
"""

def default_queue_name():
try:
return settings.DATABASE_NAME
except AttributeError:
try:
return settings.DATABASES['default']['NAME']
except KeyError:
return 'huey'

def config_error(msg):
print(configuration_message)
print('\n\n')
print(msg)
sys.exit(1)

HUEY = getattr(settings, 'HUEY', None)
if HUEY is None:
try:
from huey import RedisHuey
except ImportError:
config_error('Error: Huey could not import the redis backend. '
'Install `redis-py`.')
else:
HUEY = RedisHuey(default_queue_name())

if isinstance(HUEY, dict):
huey_config = HUEY.copy() # Operate on a copy.
name = huey_config.pop('name', default_queue_name())
conn_kwargs = huey_config.pop('connection', {})
try:
del huey_config['consumer'] # Don't need consumer opts here.
except KeyError:
pass
if 'always_eager' not in huey_config:
huey_config['always_eager'] = settings.DEBUG
huey_config.update(conn_kwargs)
HUEY = RedisHuey(name, **huey_config)

task = HUEY.task
periodic_task = HUEY.periodic_task

def close_db(fn):
"""Decorator to be used with tasks that may operate on the database."""
@wraps(fn)
def inner(*args, **kwargs):
try:
return fn(*args, **kwargs)
finally:
connection.close()
return inner

def db_task(*args, **kwargs):
def decorator(fn):
return task(*args, **kwargs)(close_db(fn))
return decorator

def db_periodic_task(*args, **kwargs):
def decorator(fn):
return periodic_task(*args, **kwargs)(close_db(fn))
return decorator
Empty file.
Empty file.
128 changes: 128 additions & 0 deletions huey/contrib/djhuey/management/commands/run_huey.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
import imp
import sys
from importlib import import_module
from optparse import make_option

from django.conf import settings
from django.core.management.base import BaseCommand

try:
from django.apps import apps as django_apps
HAS_DJANGO_APPS = True
except ImportError:
# Django 1.6
HAS_DJANGO_APPS = False

from huey.consumer import Consumer
from huey.bin.huey_consumer import get_loglevel
from huey.bin.huey_consumer import setup_logger


class Command(BaseCommand):
"""
Queue consumer. Example usage::
To start the consumer (note you must export the settings module):
django-admin.py run_huey
"""
help = "Run the queue consumer"

option_list = BaseCommand.option_list + (
make_option('--workers', '-w',
dest='workers',
type='int',
help='Number of worker threads/processes/greenlets'
),
make_option('--worker-type', '-k',
dest='worker_type',
help='worker execution model (thread, greenlet, process).',
default='thread',
choices=['greenlet', 'thread', 'process', 'gevent'],
),
make_option('--delay', '-d',
dest='initial_delay',
type='float',
help='Delay between polling requests'
),
make_option('--max_delay', '-m',
dest='max_delay',
type='float',
help='Maximum delay between polling requests'
),
make_option('--no-periodic', '-n',
default=True,
dest='periodic',
action='store_false',
help='Do not enqueue periodic commands'
),
)

def autodiscover_appconfigs(self):
"""Use Django app registry to pull out potential apps with tasks.py module."""
module_name = 'tasks'
for config in django_apps.get_app_configs():
app_path = config.module.__path__
try:
fp, path, description = imp.find_module(module_name, app_path)
except ImportError:
continue
else:
import_path = '%s.%s' % (config.name, module_name)
imp.load_module(import_path, fp, path, description)

def autodiscover_old(self):
# this is to find modules named <commands.py> in a django project's
# installed apps directories
module_name = 'tasks'

for app in settings.INSTALLED_APPS:
try:
import_module(app)
app_path = sys.modules[app].__path__
except AttributeError:
continue
try:
imp.find_module(module_name, app_path)
except ImportError:
continue
import_module('%s.%s' % (app, module_name))
app_path = sys.modules['%s.%s' % (app, module_name)]

def autodiscover(self):
"""Switch between Django 1.7 style and old style app importing."""
if HAS_DJANGO_APPS:
self.autodiscover_appconfigs()
else:
self.autodiscover_old()

def handle(self, *args, **options):
from huey.contrib.djhuey import HUEY

consumer_options = {}
if isinstance(settings.HUEY, dict):
consumer_options.update(settings.HUEY.get('consumer', {}))

if options['workers'] is not None:
consumer_options['workers'] = options['workers']

if options['worker_type'] is not None:
consumer_options['worker_type'] = options['worker_type']

if options['periodic'] is not None:
consumer_options['periodic'] = options['periodic']

if options['initial_delay'] is not None:
consumer_options['initial_delay'] = options['initial_delay']

if options['max_delay'] is not None:
consumer_options['max_delay'] = options['max_delay']

self.autodiscover()

loglevel = get_loglevel(consumer_options.pop('loglevel', None))
logfile = consumer_options.pop('logfile', None)
setup_logger(loglevel, logfile, consumer_options['worker_type'])

consumer = Consumer(HUEY, **consumer_options)
consumer.run()
Empty file added huey/contrib/djhuey/models.py
Empty file.

0 comments on commit 1e28065

Please sign in to comment.