|
|
|
import ast
|
|
|
|
|
|
|
|
from celery import signals
|
|
|
|
from django.core.cache import cache
|
|
|
|
from django.db import transaction
|
|
|
|
from django.db.models.signals import pre_save
|
|
|
|
from django.db.utils import ProgrammingError
|
|
|
|
from django.dispatch import receiver
|
|
|
|
from django.utils import translation, timezone
|
|
|
|
from django.utils.translation import gettext as _
|
|
|
|
|
|
|
|
from common.db.utils import close_old_connections, get_logger
|
|
|
|
from .celery import app
|
|
|
|
from .models import CeleryTaskExecution, CeleryTask, Job
|
|
|
|
|
|
|
|
logger = get_logger(__name__)
|
|
|
|
|
|
|
|
TASK_LANG_CACHE_KEY = 'TASK_LANG_{}'
|
|
|
|
TASK_LANG_CACHE_TTL = 1800
|
|
|
|
|
|
|
|
|
|
|
|
@receiver(pre_save, sender=Job)
|
|
|
|
def on_account_pre_create(sender, instance, **kwargs):
|
|
|
|
# 升级版本号
|
|
|
|
instance.version += 1
|
|
|
|
|
|
|
|
|
|
|
|
@receiver(signals.worker_ready)
|
|
|
|
def sync_registered_tasks(*args, **kwargs):
|
|
|
|
synced = cache.get('synced_registered_tasks', False)
|
|
|
|
if synced:
|
|
|
|
return
|
|
|
|
cache.set('synced_registered_tasks', True, 60)
|
|
|
|
with transaction.atomic():
|
|
|
|
try:
|
|
|
|
db_tasks = CeleryTask.objects.all()
|
|
|
|
celery_task_names = [key for key in app.tasks]
|
|
|
|
db_task_names = db_tasks.values_list('name', flat=True)
|
|
|
|
|
|
|
|
db_tasks.exclude(name__in=celery_task_names).delete()
|
|
|
|
not_in_db_tasks = set(celery_task_names) - set(db_task_names)
|
|
|
|
tasks_to_create = [CeleryTask(name=name) for name in not_in_db_tasks]
|
|
|
|
CeleryTask.objects.bulk_create(tasks_to_create)
|
|
|
|
except ProgrammingError:
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
@signals.before_task_publish.connect
|
|
|
|
def before_task_publish(headers=None, **kwargs):
|
|
|
|
task_id = headers.get('id')
|
|
|
|
current_lang = translation.get_language()
|
|
|
|
key = TASK_LANG_CACHE_KEY.format(task_id)
|
|
|
|
cache.set(key, current_lang, 1800)
|
|
|
|
|
|
|
|
|
|
|
|
@signals.task_prerun.connect
|
|
|
|
def on_celery_task_pre_run(task_id='', **kwargs):
|
|
|
|
# 更新状态
|
|
|
|
CeleryTaskExecution.objects.filter(id=task_id) \
|
|
|
|
.update(state='RUNNING', date_start=timezone.now())
|
|
|
|
# 关闭之前的数据库连接
|
|
|
|
close_old_connections()
|
|
|
|
|
|
|
|
# 保存 Lang context
|
|
|
|
key = TASK_LANG_CACHE_KEY.format(task_id)
|
|
|
|
task_lang = cache.get(key)
|
|
|
|
if task_lang:
|
|
|
|
translation.activate(task_lang)
|
|
|
|
|
|
|
|
|
|
|
|
@signals.task_postrun.connect
|
|
|
|
def on_celery_task_post_run(task_id='', state='', **kwargs):
|
|
|
|
close_old_connections()
|
|
|
|
print(_("Task") + ": {} {}".format(task_id, state))
|
|
|
|
|
|
|
|
CeleryTaskExecution.objects.filter(id=task_id).update(
|
|
|
|
state=state, date_finished=timezone.now(), is_finished=True
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
@signals.after_task_publish.connect
|
|
|
|
def task_sent_handler(headers=None, body=None, **kwargs):
|
|
|
|
info = headers if 'task' in headers else body
|
|
|
|
task = info.get('task')
|
|
|
|
i = info.get('id')
|
|
|
|
if not i or not task:
|
|
|
|
logger.error("Not found task id or name: {}".format(info))
|
|
|
|
return
|
|
|
|
|
|
|
|
args = info.get('argsrepr', '()')
|
|
|
|
kwargs = info.get('kwargsrepr', '{}')
|
|
|
|
try:
|
|
|
|
args = list(ast.literal_eval(args))
|
|
|
|
kwargs = ast.literal_eval(kwargs)
|
|
|
|
except (ValueError, SyntaxError):
|
|
|
|
args = []
|
|
|
|
kwargs = {}
|
|
|
|
|
|
|
|
data = {
|
|
|
|
'id': i,
|
|
|
|
'name': task,
|
|
|
|
'state': 'PENDING',
|
|
|
|
'is_finished': False,
|
|
|
|
'args': args,
|
|
|
|
'kwargs': kwargs
|
|
|
|
}
|
|
|
|
CeleryTaskExecution.objects.create(**data)
|
|
|
|
CeleryTask.objects.filter(name=task).update(last_published_time=timezone.now())
|