Files
django-q2/django_q/brokers/__init__.py
sinowoodandStan Triepels 52c04217e9 Multiple queue, multiple cluster in one site (#71)
* Support for multi-queue, multi-cluster configuration. API changes include:
  * Adding `cluster` to async_task() parameters and Task model
  * Adding argument --name to qcluster command
  * Necessary adjustments to Conf and Broker classes
  * Some admin improvements

* Add settings.Q_CLUSTER['ALT_CLUSTERS']: q_cluster config overrides for alternative clusters;
Add Conf.CLUSTER_NAME: separate usage from Conf.PREFIX;
QueueAdmin/OrmQ detail page enhanced: now displaying args/kwargs/q_options instead of encrypted payload.

* if `cluster` argument is not set (the default), async_task() and schedule() will be handled by the default cluster; Documentation update.

* Text cleanup

* Documentation update.

* Fix TIMEOUT setting in Windows for non-default cluster

---------

Co-authored-by: Stan Triepels <1939656+GDay@users.noreply.github.com>
2023-04-02 16:36:17 +02:00

204 lines
5.0 KiB
Python

import importlib
from typing import Optional
from django.core.cache import InvalidCacheBackendError, caches
from django_q.conf import Conf
class Broker:
def __init__(self, list_key: str = None):
# With same BROKER_CLASS, `list_key` is just a synonym for `queue_name` except for RedisBroker
list_key = list_key or Conf.CLUSTER_NAME
self.connection = self.get_connection(list_key)
self.list_key = list_key
self.cache = self.get_cache()
self._info = None
def __getstate__(self):
return self.list_key, self._info
def __setstate__(self, state):
self.list_key, self._info = state
self.connection = self.get_connection(self.list_key)
self.cache = self.get_cache()
def enqueue(self, task):
"""
Puts a task onto the queue
:type task: str
:return: task id
"""
pass
def dequeue(self):
"""
Gets a task from the queue
:return: tuple with task id and task message
"""
pass
def queue_size(self):
"""
:return: the amount of tasks in the queue
"""
pass
def lock_size(self):
"""
:return: the number of tasks currently awaiting acknowledgement
"""
def delete_queue(self):
"""
Deletes the queue from the broker
"""
pass
def purge_queue(self):
"""
Purges the queue of any tasks
"""
pass
def delete(self, task_id):
"""
Deletes a task from the queue
:param task_id: the id of the task
"""
pass
def acknowledge(self, task_id):
"""
Acknowledges completion of the task and removes it from the queue.
:param task_id: the id of the task
"""
pass
def fail(self, task_id):
"""
Fails a task message
:param task_id:
:return:
"""
def ping(self) -> bool:
"""
Checks whether the broker connection is available
:rtype: bool
"""
pass
def info(self):
"""
Shows the broker type
"""
return self._info
def set_stat(self, key: str, value: str, timeout: int):
"""
Saves a cluster statistic to the cache provider
:type key: str
:type value: str
:type timeout: int
"""
if not self.cache:
return
key_list = self.cache.get(Conf.Q_STAT, [])
if key not in key_list:
key_list.append(key)
self.cache.set(Conf.Q_STAT, key_list)
return self.cache.set(key, value, timeout)
def get_stat(self, key: str):
"""
Gets a cluster statistic from the cache provider
:type key: str
:return: a cluster Stat
"""
if not self.cache:
return
return self.cache.get(key)
def get_stats(self, pattern: str) -> Optional[list]:
"""
Returns a list of all cluster stats from the cache provider
:type pattern: str
:return: a list of Stats
"""
if not self.cache:
return
key_list = self.cache.get(Conf.Q_STAT)
if not key_list or len(key_list) == 0:
return []
stats = []
for key in key_list:
stat = self.cache.get(key)
if stat:
stats.append(stat)
else:
key_list.remove(key)
self.cache.set(Conf.Q_STAT, key_list)
return stats
@staticmethod
def get_cache():
"""
Gets the current cache provider
:return: a cache provider
"""
try:
return caches[Conf.CACHE]
except InvalidCacheBackendError:
return None
@staticmethod
def get_connection(list_key: str = None):
"""
Gets a connection to the broker
:param list_key: Optional queue name
:return: a broker connection
"""
return 0
def get_broker(list_key: str = None) -> Broker:
"""
Gets the configured broker type
:param list_key: optional queue name
:type list_key: str
:return: a broker instance
"""
list_key = list_key or Conf.CLUSTER_NAME
# custom
if Conf.BROKER_CLASS:
module, func = Conf.BROKER_CLASS.rsplit(".", 1)
m = importlib.import_module(module)
broker = getattr(m, func)
return broker(list_key=list_key)
# Iron MQ
elif Conf.IRON_MQ:
from django_q.brokers import ironmq
return ironmq.IronMQBroker(list_key=list_key)
# SQS
elif type(Conf.SQS) == dict:
from django_q.brokers import aws_sqs
return aws_sqs.Sqs(list_key=list_key)
# ORM
elif Conf.ORM:
from django_q.brokers import orm
return orm.ORM(list_key=list_key)
# Mongo
elif Conf.MONGO:
from django_q.brokers import mongo
return mongo.Mongo(list_key=list_key)
# default to redis
else:
from django_q.brokers import redis_broker
return redis_broker.Redis(list_key=list_key)