GithubHelp home page GithubHelp logo

apgsga / hueyx Goto Github PK

View Code? Open in Web Editor NEW
13.0 3.0 4.0 75 KB

Django extension to integrate huey with multiple queues.

License: MIT License

Python 98.53% Dockerfile 1.47%
django huey django-extensions

hueyx's Introduction

hueyx

PyPI version

A django extension to run huey with multiple queues. Multiple queues allow tasks to not block each other and to scale independently. Only the redis storage is supported.


Important
  • If you use huey 1.x then install hueyx 0.1.2. Checkout the git tag huey1.x.
  • If you use huey 2.x then install hueyx >= 1.0.

Usage

Install it with

pip install hueyx

Add hueyx in your installed apps.

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'hueyx',
]
settings.py

Compared to djhuey, hueyx allows several queues to be defined in the settings.py.

HUEYX = {
    'queue_name1': {
        'connection': {
            'host': 'localhost',
            'port': 6379,
            'db': 0,
        },
        'consumer': {
            'workers': 1,
            'worker_type': 'process',
        }
    },
    'queue_name2': {
        'connection': {
            'connection_pool': ConnectionPool(host='localhost', port=6379, db=1)
        },
        'consumer': {
            'multiple_scheduler_locking': True,
            'prometheus_metrics': True,
            'workers': 2,
            'worker_type': 'thread',
        }
    },
    'priority_queue_name3': {
        'huey_class': 'huey.PriorityRedisHuey',
        'connection': {
            'connection_pool': ConnectionPool(host='localhost', port=6379, db=1)
        },
        'consumer': {
            'multiple_scheduler_locking': True,
            'prometheus_metrics': True,
            'workers': 2,
            'worker_type': 'thread',
        }
    },
}

The settings are almost the same as in djhuey. Have a look at the huey documentation to see the exact parameter usage.

Exceptions:

  • You can only configure redis as storage engine by configure huey_class to huey.RedisHuey, huey.PriorityRedisHuey, huey.RedisExpireHuey or huey.PriorityRedisExpireHuey.
  • The name and backend_class parameters are not supported.
  • The options multiple_scheduler_locking and prometheus_metrics_enabled have been added. See below.
  • The parameters heartbeat_timeout for db_task has been added. See below.
tasks.py
from hueyx.queues import hueyx

"""
Define which queue you want to use.
They are predefined in settings.py.
"""
HUEY_Q1 = hueyx('queue_name1')
HUEY_Q2 = hueyx('queue_name2')


@HUEY_Q1.task()
def my_task1():
    print('my_task1 called')
    
@HUEY_Q1.db_task()
def my_db_task1():
    print('my_db_task1 called')
    
@HUEY_Q2.task()
def my_task2():
    print('my_task2 called')

@HUEY_Q2.periodic_task(crontab(minute='0', hour='3'))
def my_periodic_task2():
    print('my_periodic_task2 called')
    return 1
    
@HUEY_Q2.db_task(heartbeat_timeout=120)
def my_heartbeat_task(heartbeat: Heartbeat):
    with heartbeat.long_running_operation():
        print('This operation can take a while -> don\'t check for heartbeats')
    print('Now we check for heartbeats -> call heartbeat() periodically')
    heartbeat()
Push task to queue
from example.tasks import my_task1, my_db_task1, my_task2


my_task1()  # Task for queue_name1
my_db_task1()  # Task for queue_name1
my_task2()  # Task for queue_name2
Run consumer

Consumers are started with the queue_name.

./manage.py run_hueyx queue_name1
Heartbeat tasks

Heartbeat tasks are tasks with the parameter heartbeat_timeout. It defines the timeout in seconds. They get a Heartbeat object which needs to be called in order to send a heartbeat to redis. If no heartbeat occurs in set timeout the task is presumed to be dead and will automatically get restarted. heartbeat_timeout needs to be at least 120 seconds. It does not work together with the parameter include_task.

Additional settings

multiple_scheduler_locking

multiple_scheduler_locking has been added to support multiple huey schedulers. If you run huey in a cloud environment, you will end up running multiple huey instances which each will schedule the periodic task. multiple_scheduler_locking prevents periodic tasks to be scheduled multiple times. It is false by default.

Huey signals

Optionally hueyx pushes all huey signals to the redis pubsub hueyx.huey2.signaling if enabled.

HUEYX_SIGNALS = {
    'enabled': True,
    'environment': 'your environment'
}

The format of the message is

{
    'environment': settings.HUEYX_SIGNALS['environment'],
    'queue': queue,
    'pid': pid,
    'signal': signal_name,
    'task': task_name
}

The environment parameter is a optional variable.

Prometheus

The huey-exporter project takes the signals und reports it to prometheus.

Collaborators

hueyx's People

Contributors

fae-apg avatar mfa147 avatar sebubu avatar severinalexb avatar shifty11 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

hueyx's Issues

Verbose Mode

Hello,

Could you clarify the use of verbose options?

Thank you in advance.

Huey 2.0 - Breaking changes

hueyx is partially build upon huey events. The huey event system has been removed with huey 2.0. Therefore, this project is currently incompatible with the current huey version.

I havent tested hueyx with huey 2.0 yet but fire_enqueued_events will fail for sure.

https://huey.readthedocs.io/en/latest/changes.html

Please use this issue to document other findings related to huey 2.0 breaking changes.

Heartbeat Review

  • Use TaskRegistry for restarts
  • Rename timeout to heartbeat_timeout
  • Hearbeat for all task types, not just db_task
  • Redis key names
  • Documentation for usage

Support for on_shutdown events

Hi,

I am not quite sure where to put the comment. hence raising it as issue.

Is there way to add support to on_shutdown event ?

My problem statement.. I have 3 different consumers but I would like to get all of their logs into one single LOG FILE with rotation handler .. Unfortunately Python logging doesn't support logging into same file from multiple process and hence it hits permission denied error. So, the recommendation by most folks is about using socket handler for streaming logs from all processes into master process and storing then to a file..

So, I am running a socket server on the a master process and that will run as soon as my consumers starts.. But, on consumer shutdown I would like to gracefully stop a socket server that I am starting as part of a task.

I looked at on_shutdown event from huey but unfortunately that doesn't seems to be helping with hueyx.

from huey.contrib.djhuey import on_shutdown

@on_shutdown()
def on_consumers_going_down():
    print("They are going down")

When using RedisExpireStorage you get the exception: `redis.exceptions.DataError: Invalid input of type: 'function'. Convert to a bytes, string, int or float first.

Basically huey.storage.RedisExpireStorage uses a lambda to define self.result_key instead of being a simple string:

class RedisExpireStorage(RedisStorage):
    # Redis storage subclass that adds expiration to task result values. Since
    # the Redis server handles deleting our results after the expiration time,
    # this storage layer will not delete the results when they are read.
    def __init__(self, name='huey', expire_time=86400, *args, **kwargs):
        super(RedisExpireStorage, self).__init__(name, *args, **kwargs)

        self._expire_time = expire_time

        self.result_prefix = rp = b'huey.r.%s.' % self.name.encode('utf8')
        encode = lambda s: s if isinstance(s, bytes) else s.encode('utf8')
        self.result_key = lambda k: rp + encode(k)

I have not looked into this any deeper at this point and have switched to PriorityRedisStorage for now.

Event Listener

Hello,

Could you help me to access the event listener using hueyx?

On native HUEY, I would have:

HUEY = RedisHuey('general', always_eager=False)

pubsub = settings.HUEY.storage.listener()

        for message in pubsub.listen():

                 ...

For the analogue HUEYX definition:

HUEYX = {'general': {
            'connection': {'connection_pool': ConnectionPool(host='localhost', port=6379, db=0)},
            'consumer': {'workers': 1, 'worker_type': 'thread'},
            'always_eager': False
        },
        'monitors': {
            'connection': {'connection_pool': ConnectionPool(host='localhost', port=6379, db=1, max_connections=20)},
            'consumer': {'workers': 10,'worker_type': 'thread'},
            'always_eager': False,
        },
}

How could I access the event listener?

Thank you in advance.

Duplicate registration of a task

I found the hueyx library because of its support for multiple_scheduler_locking.

I was able to use it successfully until I tried to import a task into views.py. Once I did that I started getting the stack trace below. I've tested and this seems to only happen with hueyx, not huey.

I've created a repo to recreate the issue: https://github.com/overtron/huey_debug/tree/master

The master branch will show the issue.
The non-hueyx branch shows that the issue does not happen with regular huey.

Happy to help fix this and submit a PR if you have some thoughts about what might be causing this to happen. I've included additional details about how to replicate the issue in the linked repository

huey-general-worker_1  | Traceback (most recent call last):
huey-general-worker_1  |   File "manage.py", line 30, in <module>
huey-general-worker_1  |     execute_from_command_line(sys.argv)
huey-general-worker_1  |   File "/usr/local/lib/python3.7/site-packages/django/core/management/__init__.py", line 381, in execute_from_command_line
huey-general-worker_1  |     utility.execute()
huey-general-worker_1  |   File "/usr/local/lib/python3.7/site-packages/django/core/management/__init__.py", line 375, in execute
huey-general-worker_1  |     self.fetch_command(subcommand).run_from_argv(self.argv)
huey-general-worker_1  |   File "/usr/local/lib/python3.7/site-packages/django/core/management/base.py", line 323, in run_from_argv
huey-general-worker_1  |     self.execute(*args, **cmd_options)
huey-general-worker_1  |   File "/usr/local/lib/python3.7/site-packages/django/core/management/base.py", line 364, in execute
huey-general-worker_1  |     output = self.handle(*args, **options)
huey-general-worker_1  |   File "/usr/local/lib/python3.7/site-packages/hueyx/management/commands/run_hueyx.py", line 63, in handle
huey-general-worker_1  |     self.autodiscover()
huey-general-worker_1  |   File "/usr/local/lib/python3.7/site-packages/hueyx/management/commands/run_hueyx.py", line 40, in autodiscover
huey-general-worker_1  |     imp.load_module(import_path, fp, path, description)
huey-general-worker_1  |   File "/usr/local/lib/python3.7/imp.py", line 234, in load_module
huey-general-worker_1  |     return load_source(name, filename, file)
huey-general-worker_1  |   File "/usr/local/lib/python3.7/imp.py", line 169, in load_source
huey-general-worker_1  |     module = _exec(spec, sys.modules[name])
huey-general-worker_1  |   File "<frozen importlib._bootstrap>", line 630, in _exec
huey-general-worker_1  |   File "<frozen importlib._bootstrap_external>", line 728, in exec_module
huey-general-worker_1  |   File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
huey-general-worker_1  |   File "/app/huey_debug/users/tasks.py", line 6, in <module>
huey-general-worker_1  |     @HUEY.task()
huey-general-worker_1  |   File "/usr/local/lib/python3.7/site-packages/huey/api.py", line 169, in decorator
huey-general-worker_1  |     **kwargs)
huey-general-worker_1  |   File "/usr/local/lib/python3.7/site-packages/huey/api.py", line 687, in __init__
huey-general-worker_1  |     self.huey._registry.register(self.task_class)
huey-general-worker_1  |   File "/usr/local/lib/python3.7/site-packages/huey/registry.py", line 24, in register
huey-general-worker_1  |     ' name= to register this task. "%s"' % task_str)
huey-general-worker_1  | ValueError: Attempting to register a task with the same identifier as existing task. Specify a different name= to register this task. "huey_debug.users.tasks.task1"
huey_debug_huey-general-worker_1 exited with code 1

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.