Updates
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
"""Celery result backends for Django."""
|
||||
# :copyright: (c) 2016, Ask Solem.
|
||||
# :copyright: (c) 2017-2033, Asif Saif Uddin.
|
||||
# All rights reserved.
|
||||
# :license: BSD (3 Clause), see LICENSE for more details.
|
||||
|
||||
import re
|
||||
from collections import namedtuple
|
||||
|
||||
import django
|
||||
|
||||
__version__ = '2.6.0'
|
||||
__author__ = 'Asif Saif Uddin'
|
||||
__contact__ = 'auvipy@gmail.com'
|
||||
__homepage__ = 'https://github.com/celery/django-celery-results'
|
||||
__docformat__ = 'restructuredtext'
|
||||
|
||||
# -eof meta-
|
||||
|
||||
version_info_t = namedtuple('version_info_t', (
|
||||
'major', 'minor', 'micro', 'releaselevel', 'serial',
|
||||
))
|
||||
|
||||
# bumpversion can only search for {current_version}
|
||||
# so we have to parse the version here.
|
||||
_temp = re.match(
|
||||
r'(\d+)\.(\d+).(\d+)(.+)?', __version__).groups()
|
||||
VERSION = version_info = version_info_t(
|
||||
int(_temp[0]), int(_temp[1]), int(_temp[2]), _temp[3] or '', '')
|
||||
del _temp
|
||||
del re
|
||||
|
||||
__all__ = []
|
||||
|
||||
if django.VERSION < (3, 2):
|
||||
default_app_config = 'django_celery_results.apps.CeleryResultConfig'
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,85 @@
|
||||
"""Result Task Admin interface."""
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib import admin
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
try:
|
||||
ALLOW_EDITS = settings.DJANGO_CELERY_RESULTS['ALLOW_EDITS']
|
||||
except (AttributeError, KeyError):
|
||||
ALLOW_EDITS = False
|
||||
pass
|
||||
|
||||
from .models import GroupResult, TaskResult
|
||||
|
||||
|
||||
class TaskResultAdmin(admin.ModelAdmin):
|
||||
"""Admin-interface for results of tasks."""
|
||||
|
||||
model = TaskResult
|
||||
date_hierarchy = 'date_done'
|
||||
list_display = ('task_id', 'periodic_task_name', 'task_name', 'date_done',
|
||||
'status', 'worker')
|
||||
list_filter = ('status', 'date_done', 'periodic_task_name', 'task_name',
|
||||
'worker')
|
||||
readonly_fields = ('date_created', 'date_started', 'date_done',
|
||||
'result', 'meta')
|
||||
search_fields = ('task_name', 'task_id', 'status', 'task_args',
|
||||
'task_kwargs')
|
||||
fieldsets = (
|
||||
(None, {
|
||||
'fields': (
|
||||
'task_id',
|
||||
'task_name',
|
||||
'periodic_task_name',
|
||||
'status',
|
||||
'worker',
|
||||
'content_type',
|
||||
'content_encoding',
|
||||
),
|
||||
'classes': ('extrapretty', 'wide')
|
||||
}),
|
||||
(_('Parameters'), {
|
||||
'fields': (
|
||||
'task_args',
|
||||
'task_kwargs',
|
||||
),
|
||||
'classes': ('extrapretty', 'wide')
|
||||
}),
|
||||
(_('Result'), {
|
||||
'fields': (
|
||||
'result',
|
||||
'date_created',
|
||||
'date_started',
|
||||
'date_done',
|
||||
'traceback',
|
||||
'meta',
|
||||
),
|
||||
'classes': ('extrapretty', 'wide')
|
||||
}),
|
||||
)
|
||||
|
||||
def get_readonly_fields(self, request, obj=None):
|
||||
if ALLOW_EDITS:
|
||||
return self.readonly_fields
|
||||
else:
|
||||
return list({
|
||||
field.name for field in self.opts.local_fields
|
||||
})
|
||||
|
||||
|
||||
admin.site.register(TaskResult, TaskResultAdmin)
|
||||
|
||||
|
||||
class GroupResultAdmin(admin.ModelAdmin):
|
||||
"""Admin-interface for results of grouped tasks."""
|
||||
|
||||
model = GroupResult
|
||||
date_hierarchy = 'date_done'
|
||||
list_display = ('group_id', 'date_done')
|
||||
list_filter = ('date_done',)
|
||||
readonly_fields = ('date_created', 'date_done', 'result')
|
||||
search_fields = ('group_id',)
|
||||
|
||||
|
||||
admin.site.register(GroupResult, GroupResultAdmin)
|
||||
@@ -0,0 +1,15 @@
|
||||
"""Application configuration."""
|
||||
|
||||
from django.apps import AppConfig
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
__all__ = ['CeleryResultConfig']
|
||||
|
||||
|
||||
class CeleryResultConfig(AppConfig):
|
||||
"""Default configuration for the django_celery_results app."""
|
||||
|
||||
name = 'django_celery_results'
|
||||
label = 'django_celery_results'
|
||||
verbose_name = _('Celery Results')
|
||||
default_auto_field = 'django.db.models.AutoField'
|
||||
@@ -0,0 +1,4 @@
|
||||
from .cache import CacheBackend
|
||||
from .database import DatabaseBackend
|
||||
|
||||
__all__ = ['CacheBackend', 'DatabaseBackend']
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,39 @@
|
||||
"""Celery cache backend using the Django Cache Framework."""
|
||||
|
||||
from celery.backends.base import KeyValueStoreBackend
|
||||
from django.core.cache import cache as default_cache
|
||||
from django.core.cache import caches
|
||||
from kombu.utils.encoding import bytes_to_str
|
||||
|
||||
|
||||
class CacheBackend(KeyValueStoreBackend):
|
||||
"""Backend using the Django cache framework to store task metadata."""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
# Must make sure backend doesn't convert exceptions to dict.
|
||||
self.serializer = 'pickle'
|
||||
|
||||
def get(self, key):
|
||||
key = bytes_to_str(key)
|
||||
return self.cache_backend.get(key)
|
||||
|
||||
def set(self, key, value):
|
||||
key = bytes_to_str(key)
|
||||
self.cache_backend.set(key, value, self.expires)
|
||||
|
||||
def delete(self, key):
|
||||
key = bytes_to_str(key)
|
||||
self.cache_backend.delete(key)
|
||||
|
||||
def encode(self, data):
|
||||
return data
|
||||
|
||||
def decode(self, data):
|
||||
return data
|
||||
|
||||
@property
|
||||
def cache_backend(self):
|
||||
backend = self.app.conf.cache_backend
|
||||
return caches[backend] if backend else default_cache
|
||||
@@ -0,0 +1,314 @@
|
||||
import binascii
|
||||
import json
|
||||
|
||||
from celery import maybe_signature, states
|
||||
from celery.backends.base import BaseDictBackend, get_current_task
|
||||
from celery.exceptions import ChordError
|
||||
from celery.result import GroupResult, allow_join_result, result_from_tuple
|
||||
from celery.utils.log import get_logger
|
||||
from celery.utils.serialization import b64decode, b64encode
|
||||
from django.db import connection, router, transaction
|
||||
from django.db.models.functions import Now
|
||||
from django.db.utils import InterfaceError
|
||||
from kombu.exceptions import DecodeError
|
||||
|
||||
from ..models import ChordCounter
|
||||
from ..models import GroupResult as GroupResultModel
|
||||
from ..models import TaskResult
|
||||
|
||||
EXCEPTIONS_TO_CATCH = (InterfaceError,)
|
||||
|
||||
try:
|
||||
from psycopg2 import InterfaceError as Psycopg2InterfaceError
|
||||
EXCEPTIONS_TO_CATCH += (Psycopg2InterfaceError,)
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
class DatabaseBackend(BaseDictBackend):
|
||||
"""The Django database backend, using models to store task state."""
|
||||
|
||||
TaskModel = TaskResult
|
||||
GroupModel = GroupResultModel
|
||||
subpolling_interval = 0.5
|
||||
|
||||
def exception_safe_to_retry(self, exc):
|
||||
"""Check if an exception is safe to retry.
|
||||
|
||||
Backends have to overload this method with correct predicates
|
||||
dealing with their exceptions.
|
||||
|
||||
By default no exception is safe to retry, it's up to
|
||||
backend implementation to define which exceptions are safe.
|
||||
|
||||
For Celery / django-celery-results, retry Django / Psycopg2
|
||||
InterfaceErrors, like "Connection already closed", with new connection.
|
||||
|
||||
Set result_backend_always_retry to True in order to enable retries.
|
||||
"""
|
||||
for exc_type in EXCEPTIONS_TO_CATCH:
|
||||
if isinstance(exc, exc_type):
|
||||
# Only called if InterfaceError occurs and always_retry is True
|
||||
connection.close()
|
||||
return True
|
||||
return False
|
||||
|
||||
def _get_extended_properties(self, request, traceback):
|
||||
extended_props = {
|
||||
'periodic_task_name': None,
|
||||
'task_args': None,
|
||||
'task_kwargs': None,
|
||||
'task_name': None,
|
||||
'traceback': None,
|
||||
'worker': None,
|
||||
}
|
||||
if request and self.app.conf.find_value_for_key('extended', 'result'):
|
||||
|
||||
if getattr(request, 'argsrepr', None) is not None:
|
||||
# task protocol 2
|
||||
task_args = request.argsrepr
|
||||
else:
|
||||
# task protocol 1
|
||||
task_args = getattr(request, 'args', None)
|
||||
|
||||
if getattr(request, 'kwargsrepr', None) is not None:
|
||||
# task protocol 2
|
||||
task_kwargs = request.kwargsrepr
|
||||
else:
|
||||
# task protocol 1
|
||||
task_kwargs = getattr(request, 'kwargs', None)
|
||||
|
||||
# Encode input arguments
|
||||
if task_args is not None:
|
||||
_, _, task_args = self.encode_content(task_args)
|
||||
|
||||
if task_kwargs is not None:
|
||||
_, _, task_kwargs = self.encode_content(task_kwargs)
|
||||
|
||||
periodic_task_name = getattr(request, 'periodic_task_name', None)
|
||||
|
||||
extended_props.update({
|
||||
'periodic_task_name': periodic_task_name,
|
||||
'task_args': task_args,
|
||||
'task_kwargs': task_kwargs,
|
||||
'task_name': getattr(request, 'task', None),
|
||||
'traceback': traceback,
|
||||
'worker': getattr(request, 'hostname', None),
|
||||
})
|
||||
|
||||
return extended_props
|
||||
|
||||
def _get_meta_from_request(self, request=None):
|
||||
"""
|
||||
Use the request or get_current_task to evaluate the `meta` attribute.
|
||||
|
||||
With this, is possible to assign arbitrary data in request.meta to be
|
||||
retrieve and stored on the TaskResult.
|
||||
"""
|
||||
request = request or getattr(get_current_task(), "request", None)
|
||||
return getattr(request, "meta", {})
|
||||
|
||||
def _store_result(
|
||||
self,
|
||||
task_id,
|
||||
result,
|
||||
status,
|
||||
traceback=None,
|
||||
request=None,
|
||||
using=None
|
||||
):
|
||||
"""Store return value and status of an executed task."""
|
||||
content_type, content_encoding, result = self.encode_content(result)
|
||||
|
||||
meta = {
|
||||
**self._get_meta_from_request(request),
|
||||
"children": self.current_task_children(request),
|
||||
}
|
||||
_, _, encoded_meta = self.encode_content(
|
||||
meta,
|
||||
)
|
||||
|
||||
task_props = {
|
||||
'content_encoding': content_encoding,
|
||||
'content_type': content_type,
|
||||
'meta': encoded_meta,
|
||||
'result': result,
|
||||
'status': status,
|
||||
'task_id': task_id,
|
||||
'traceback': traceback,
|
||||
'using': using,
|
||||
}
|
||||
|
||||
task_props.update(
|
||||
self._get_extended_properties(request, traceback)
|
||||
)
|
||||
|
||||
if status == states.STARTED:
|
||||
task_props['date_started'] = Now()
|
||||
|
||||
self.TaskModel._default_manager.store_result(**task_props)
|
||||
return result
|
||||
|
||||
def _get_task_meta_for(self, task_id):
|
||||
"""Get task metadata for a task by id."""
|
||||
obj = self.TaskModel._default_manager.get_task(task_id)
|
||||
res = obj.as_dict()
|
||||
meta = self.decode_content(obj, res.pop('meta', None)) or {}
|
||||
result = self.decode_content(obj, res.get('result'))
|
||||
|
||||
task_args = res.get('task_args')
|
||||
task_kwargs = res.get('task_kwargs')
|
||||
try:
|
||||
task_args = self.decode_content(obj, task_args)
|
||||
task_kwargs = self.decode_content(obj, task_kwargs)
|
||||
except (DecodeError, binascii.Error):
|
||||
pass
|
||||
|
||||
# the right names are args/kwargs, not task_args/task_kwargs,
|
||||
# keep both for backward compatibility
|
||||
res.update(
|
||||
meta,
|
||||
result=result,
|
||||
task_args=task_args,
|
||||
task_kwargs=task_kwargs,
|
||||
args=task_args,
|
||||
kwargs=task_kwargs,
|
||||
)
|
||||
return self.meta_from_decoded(res)
|
||||
|
||||
def encode_content(self, data):
|
||||
content_type, content_encoding, content = self._encode(data)
|
||||
if content_encoding == 'binary':
|
||||
content = b64encode(content)
|
||||
return content_type, content_encoding, content
|
||||
|
||||
def decode_content(self, obj, content):
|
||||
if content:
|
||||
if obj.content_encoding == 'binary':
|
||||
content = b64decode(content)
|
||||
return self.decode(content)
|
||||
|
||||
def _forget(self, task_id):
|
||||
try:
|
||||
self.TaskModel._default_manager.get(task_id=task_id).delete()
|
||||
except self.TaskModel.DoesNotExist:
|
||||
pass
|
||||
|
||||
def cleanup(self):
|
||||
"""Delete expired metadata."""
|
||||
if not self.expires:
|
||||
return
|
||||
self.TaskModel._default_manager.delete_expired(self.expires)
|
||||
self.GroupModel._default_manager.delete_expired(self.expires)
|
||||
|
||||
def _restore_group(self, group_id):
|
||||
"""return result value for a group by id."""
|
||||
group_result = self.GroupModel._default_manager.get_group(group_id)
|
||||
|
||||
if group_result:
|
||||
res = group_result.as_dict()
|
||||
decoded_result = self.decode_content(group_result, res["result"])
|
||||
res["result"] = None
|
||||
if decoded_result:
|
||||
res["result"] = result_from_tuple(decoded_result, app=self.app)
|
||||
return res
|
||||
|
||||
def _save_group(self, group_id, group_result):
|
||||
"""Store return value of group"""
|
||||
content_type, content_encoding, result = self.encode_content(
|
||||
group_result.as_tuple()
|
||||
)
|
||||
self.GroupModel._default_manager.store_group_result(
|
||||
content_type, content_encoding, group_id, result
|
||||
)
|
||||
return group_result
|
||||
|
||||
def _delete_group(self, group_id):
|
||||
try:
|
||||
self.GroupModel._default_manager.get_group(group_id).delete()
|
||||
except self.TaskModel.DoesNotExist:
|
||||
pass
|
||||
|
||||
def apply_chord(self, header_result_args, body, **kwargs):
|
||||
"""Add a ChordCounter with the expected number of results"""
|
||||
if not isinstance(header_result_args, GroupResult):
|
||||
# Celery 5.1 provides the GroupResult args
|
||||
header_result = self.app.GroupResult(*header_result_args)
|
||||
else:
|
||||
# celery <5.1 will pass a GroupResult object
|
||||
header_result = header_result_args
|
||||
results = [r.as_tuple() for r in header_result]
|
||||
chord_size = body.get("chord_size", None) or len(results)
|
||||
data = json.dumps(results)
|
||||
ChordCounter.objects.create(
|
||||
group_id=header_result.id, sub_tasks=data, count=chord_size
|
||||
)
|
||||
|
||||
def on_chord_part_return(self, request, state, result, **kwargs):
|
||||
"""Called on finishing each part of a Chord header"""
|
||||
tid, gid = request.id, request.group
|
||||
if not gid or not tid:
|
||||
return
|
||||
call_callback = False
|
||||
with transaction.atomic(using=router.db_for_write(ChordCounter)):
|
||||
# We need to know if `count` hits 0.
|
||||
# wrap the update in a transaction
|
||||
# with a `select_for_update` lock to prevent race conditions.
|
||||
# SELECT FOR UPDATE is not supported on all databases
|
||||
try:
|
||||
chord_counter = (
|
||||
ChordCounter.objects.select_for_update()
|
||||
.get(group_id=gid)
|
||||
)
|
||||
except ChordCounter.DoesNotExist:
|
||||
logger.warning("Can't find ChordCounter for Group %s", gid)
|
||||
return
|
||||
chord_counter.count -= 1
|
||||
if chord_counter.count != 0:
|
||||
chord_counter.save(update_fields=["count"])
|
||||
else:
|
||||
# Last task in the chord header has finished
|
||||
call_callback = True
|
||||
chord_counter.delete()
|
||||
|
||||
if call_callback:
|
||||
deps = chord_counter.group_result(app=self.app)
|
||||
if deps.ready():
|
||||
callback = maybe_signature(request.chord, app=self.app)
|
||||
trigger_callback(
|
||||
app=self.app,
|
||||
callback=callback,
|
||||
group_result=deps
|
||||
)
|
||||
|
||||
|
||||
def trigger_callback(app, callback, group_result):
|
||||
"""Add the callback to the queue or mark the callback as failed
|
||||
Implementation borrowed from `celery.app.builtins.unlock_chord`
|
||||
"""
|
||||
if group_result.supports_native_join:
|
||||
j = group_result.join_native
|
||||
else:
|
||||
j = group_result.join
|
||||
|
||||
try:
|
||||
with allow_join_result():
|
||||
ret = j(timeout=app.conf.result_chord_join_timeout, propagate=True)
|
||||
except Exception as exc: # pylint: disable=broad-except
|
||||
try:
|
||||
culprit = next(group_result._failed_join_report())
|
||||
reason = f"Dependency {culprit.id} raised {exc!r}"
|
||||
except StopIteration:
|
||||
reason = repr(exc)
|
||||
logger.exception("Chord %r raised: %r", group_result.id, exc)
|
||||
app.backend.chord_error_from_stack(callback, ChordError(reason))
|
||||
else:
|
||||
try:
|
||||
callback.delay(ret)
|
||||
except Exception as exc: # pylint: disable=broad-except
|
||||
logger.exception("Chord %r raised: %r", group_result.id, exc)
|
||||
app.backend.chord_error_from_stack(
|
||||
callback, exc=ChordError(f"Callback error: {exc!r}")
|
||||
)
|
||||
@@ -0,0 +1,150 @@
|
||||
# Spanish translation strings for django-celery-results.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as django-celery-results.
|
||||
# <mondejar1994@gmail.com>, 2020.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version:\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2020-02-26 18:34+0100\n"
|
||||
"PO-Revision-Date: 2020-02-26 20:25-0015\n"
|
||||
"Last-Translator: <mondejar1994@gmail.com>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"Language: es\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: django_celery_results/admin.py:39
|
||||
msgid "Parameters"
|
||||
msgstr "Parámetros"
|
||||
|
||||
#: django_celery_results/admin.py:46
|
||||
msgid "Result"
|
||||
msgstr "Resultado"
|
||||
|
||||
#: django_celery_results/apps.py:15
|
||||
msgid "Celery Results"
|
||||
msgstr "Resultados Celery"
|
||||
|
||||
#: django_celery_results/models.py:28
|
||||
msgid "Task ID"
|
||||
msgstr "ID de Tarea"
|
||||
|
||||
#: django_celery_results/models.py:29
|
||||
msgid "Celery ID for the Task that was run"
|
||||
msgstr "ID de Celery para la tarea que fue ejecutada"
|
||||
|
||||
#: django_celery_results/models.py:32
|
||||
msgid "Task Name"
|
||||
msgstr "Nombre de Tarea"
|
||||
|
||||
#: django_celery_results/models.py:33
|
||||
msgid "Name of the Task which was run"
|
||||
msgstr "Nombre de la Tarea que fue ejecutada"
|
||||
|
||||
#: django_celery_results/models.py:36
|
||||
msgid "Task Positional Arguments"
|
||||
msgstr "Argumentos posicionales de la Tarea"
|
||||
|
||||
#: django_celery_results/models.py:37
|
||||
msgid "JSON representation of the positional arguments used with the task"
|
||||
msgstr "Representación JSON de los argumentos posicionales usados en la tarea"
|
||||
|
||||
#: django_celery_results/models.py:41
|
||||
msgid "Task Named Arguments"
|
||||
msgstr "Argumentos opcionales de la tarea"
|
||||
|
||||
#: django_celery_results/models.py:42
|
||||
msgid "JSON representation of the named arguments used with the task"
|
||||
msgstr "Representación JSON de los argumentos opcionales usados en la tarea"
|
||||
|
||||
#: django_celery_results/models.py:47
|
||||
msgid "Task State"
|
||||
msgstr "Estado de la Tarea"
|
||||
|
||||
#: django_celery_results/models.py:48
|
||||
msgid "Current state of the task being run"
|
||||
msgstr "Estado actual en el que se encuentra la tarea en ejecución"
|
||||
|
||||
#: django_celery_results/models.py:51
|
||||
msgid "Worker"
|
||||
msgstr "Worker"
|
||||
|
||||
#: django_celery_results/models.py:51
|
||||
msgid "Worker that executes the task"
|
||||
msgstr "Worker que ejecuta la tarea"
|
||||
|
||||
#: django_celery_results/models.py:55
|
||||
msgid "Result Content Type"
|
||||
msgstr "Content Type del resultado"
|
||||
|
||||
#: django_celery_results/models.py:56
|
||||
msgid "Content type of the result data"
|
||||
msgstr "Atributo Content type de los datos del resultado"
|
||||
|
||||
#: django_celery_results/models.py:59
|
||||
msgid "Result Encoding"
|
||||
msgstr "Codificación del resultado"
|
||||
|
||||
#: django_celery_results/models.py:60
|
||||
msgid "The encoding used to save the task result data"
|
||||
msgstr "La codificación usada para guardar los datos del resultado"
|
||||
|
||||
#: django_celery_results/models.py:63
|
||||
msgid "Result Data"
|
||||
msgstr "Datos del resultado"
|
||||
|
||||
#: django_celery_results/models.py:64
|
||||
msgid ""
|
||||
"The data returned by the task. Use content_encoding and content_type fields"
|
||||
" to read."
|
||||
msgstr ""
|
||||
"Datos devueltos por la tarea. Usa los campos content_encoding y content_type"
|
||||
" para leerlos."
|
||||
|
||||
#: django_celery_results/models.py:68
|
||||
msgid "Created DateTime"
|
||||
msgstr "Fecha de creación"
|
||||
|
||||
#: django_celery_results/models.py:69
|
||||
msgid "Datetime field when the task result was created in UTC"
|
||||
msgstr "Fecha de creación de la tarea en UTC"
|
||||
|
||||
#: django_celery_results/models.py:72
|
||||
msgid "Completed DateTime"
|
||||
msgstr "Fecha de terminación"
|
||||
|
||||
#: django_celery_results/models.py:73
|
||||
msgid "Datetime field when the task was completed in UTC"
|
||||
msgstr "Fecha de completitud de la tarea en UTC"
|
||||
|
||||
#: django_celery_results/models.py:76
|
||||
msgid "Traceback"
|
||||
msgstr "Traceback"
|
||||
|
||||
#: django_celery_results/models.py:77
|
||||
msgid "Text of the traceback if the task generated one"
|
||||
msgstr "Texto del traceback si la tarea generó uno"
|
||||
|
||||
#: django_celery_results/models.py:80
|
||||
msgid "Task Meta Information"
|
||||
msgstr "Metadatos de la tarea"
|
||||
|
||||
#: django_celery_results/models.py:81
|
||||
msgid ""
|
||||
"JSON meta information about the task, such as information on child tasks"
|
||||
msgstr ""
|
||||
"Metainformación sobre la tarea en formato JSON, como la información de las "
|
||||
"tareas hijas"
|
||||
|
||||
#: django_celery_results/models.py:91
|
||||
msgid "task result"
|
||||
msgstr "resultado de la tarea"
|
||||
|
||||
#: django_celery_results/models.py:92
|
||||
msgid "task results"
|
||||
msgstr "resultados de tareas"
|
||||
@@ -0,0 +1,191 @@
|
||||
# Brazilian portuguese translation strings for django-celery-results.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as django-celery-results.
|
||||
# Eduardo Oliveira <eduardo_y05@outlook.com>, 2022.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2022-01-04 19:52-0300\n"
|
||||
"PO-Revision-Date: 2022-01-04 19:52-0300\n"
|
||||
"Last-Translator: Eduardo Oliveira <eduardo_y05@outlook.com>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"Language: pt_BR\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
|
||||
#: admin.py:40
|
||||
msgid "Parameters"
|
||||
msgstr "Parâmetros"
|
||||
|
||||
#: admin.py:47
|
||||
msgid "Result"
|
||||
msgstr "Resultado"
|
||||
|
||||
#: apps.py:14
|
||||
msgid "Celery Results"
|
||||
msgstr "Resultados do celery"
|
||||
|
||||
#: models.py:28
|
||||
msgid "Task ID"
|
||||
msgstr "Id da tarefa"
|
||||
|
||||
#: models.py:29
|
||||
msgid "Celery ID for the Task that was run"
|
||||
msgstr "Id do celery em que a tarefa foi executada"
|
||||
|
||||
#: models.py:32
|
||||
msgid "Periodic Task Name"
|
||||
msgstr "Nome da tarefa periódica"
|
||||
|
||||
#: models.py:33
|
||||
msgid "Name of the Periodic Task which was run"
|
||||
msgstr "Nome da tarefa periódica que foi executada"
|
||||
|
||||
#: models.py:36
|
||||
msgid "Task Name"
|
||||
msgstr "Nome da tarefa"
|
||||
|
||||
#: models.py:37
|
||||
msgid "Name of the Task which was run"
|
||||
msgstr "Nome da tarefa que foi executada"
|
||||
|
||||
#: models.py:40
|
||||
msgid "Task Positional Arguments"
|
||||
msgstr "Argumentos posicionais da tarefa"
|
||||
|
||||
#: models.py:41
|
||||
msgid "JSON representation of the positional arguments used with the task"
|
||||
msgstr "Representação JSON dos argumentos posicionais usados pela tarefa"
|
||||
|
||||
#: models.py:45
|
||||
msgid "Task Named Arguments"
|
||||
msgstr "Argumentos nomeados da tarefa"
|
||||
|
||||
#: models.py:46
|
||||
msgid "JSON representation of the named arguments used with the task"
|
||||
msgstr "Representação JSON dos argumentos nomeados usados pela tarefa"
|
||||
|
||||
#: models.py:51
|
||||
msgid "Task State"
|
||||
msgstr "Status da tarefa"
|
||||
|
||||
#: models.py:52
|
||||
msgid "Current state of the task being run"
|
||||
msgstr "Status atual da tarefa em execução"
|
||||
|
||||
#: models.py:55
|
||||
msgid "Worker"
|
||||
msgstr "Worker"
|
||||
|
||||
#: models.py:55
|
||||
msgid "Worker that executes the task"
|
||||
msgstr "Worker que executa a tarefa"
|
||||
|
||||
#: models.py:59 models.py:190
|
||||
msgid "Result Content Type"
|
||||
msgstr "Tipo de conteúdo do resultado"
|
||||
|
||||
#: models.py:60 models.py:191
|
||||
msgid "Content type of the result data"
|
||||
msgstr "Tipo de conteúdo dos dados do resultado"
|
||||
|
||||
#: models.py:63 models.py:195
|
||||
msgid "Result Encoding"
|
||||
msgstr "Codificação do resultado"
|
||||
|
||||
#: models.py:64 models.py:196
|
||||
msgid "The encoding used to save the task result data"
|
||||
msgstr "A codificação usada para salvar os dados de resultado da tarefa"
|
||||
|
||||
#: models.py:67 models.py:200
|
||||
msgid "Result Data"
|
||||
msgstr "Dados do resultado"
|
||||
|
||||
#: models.py:68 models.py:201
|
||||
msgid ""
|
||||
"The data returned by the task. Use content_encoding and content_type fields "
|
||||
"to read."
|
||||
msgstr "Os dados retornados pela tarefa. Use os campos content_encoding e content_type para ler."
|
||||
|
||||
#: models.py:72 models.py:180
|
||||
msgid "Created DateTime"
|
||||
msgstr "Data/Horário de criação"
|
||||
|
||||
#: models.py:73
|
||||
msgid "Datetime field when the task result was created in UTC"
|
||||
msgstr "Data/Horário em que o resultado da tarefa foi criado (em UTC)"
|
||||
|
||||
#: models.py:76 models.py:185
|
||||
msgid "Completed DateTime"
|
||||
msgstr "Data/Horário em que foi concluída"
|
||||
|
||||
#: models.py:77
|
||||
msgid "Datetime field when the task was completed in UTC"
|
||||
msgstr "Data/Horário em que a tarefa foi concluída (em UTC)"
|
||||
|
||||
#: models.py:80
|
||||
msgid "Traceback"
|
||||
msgstr "Traceback"
|
||||
|
||||
#: models.py:81
|
||||
msgid "Text of the traceback if the task generated one"
|
||||
msgstr "Texto de traceback se a tarefa gerou um"
|
||||
|
||||
#: models.py:84
|
||||
msgid "Task Meta Information"
|
||||
msgstr "Meta informação da tarefa"
|
||||
|
||||
#: models.py:85
|
||||
msgid ""
|
||||
"JSON meta information about the task, such as information on child tasks"
|
||||
msgstr "Meta informação JSON sobre a tarefa, como informações sobre as subtarefas"
|
||||
|
||||
#: models.py:95
|
||||
msgid "task result"
|
||||
msgstr "resultado da tarefa"
|
||||
|
||||
#: models.py:96
|
||||
msgid "task results"
|
||||
msgstr "resultados das tarefas"
|
||||
|
||||
#: models.py:133 models.py:175
|
||||
msgid "Group ID"
|
||||
msgstr "Id do grupo"
|
||||
|
||||
#: models.py:134
|
||||
msgid "Celery ID for the Chord header group"
|
||||
msgstr "Id do celery para o grupo de cabeçalho Chord"
|
||||
|
||||
#: models.py:138
|
||||
msgid ""
|
||||
"JSON serialized list of task result tuples. use .group_result() to decode"
|
||||
msgstr "lista de tuplas de resultados de tarefas serializadas como JSON. Use .group_result() para decodificar"
|
||||
|
||||
#: models.py:144
|
||||
msgid "Starts at len(chord header) and decrements after each task is finished"
|
||||
msgstr "Começa em len(chord header) e decaí após o término de cada tarefa"
|
||||
|
||||
#: models.py:176
|
||||
msgid "Celery ID for the Group that was run"
|
||||
msgstr "Id do celery para o grupo que foi executado"
|
||||
|
||||
#: models.py:181
|
||||
msgid "Datetime field when the group result was created in UTC"
|
||||
msgstr "Data/Horário em que o resultado do grupo foi criado (em UTC)"
|
||||
|
||||
#: models.py:186
|
||||
msgid "Datetime field when the group was completed in UTC"
|
||||
msgstr "Data/Horário em que o grupo foi concluída (em UTC)"
|
||||
|
||||
#: models.py:221
|
||||
msgid "group result"
|
||||
msgstr "resultado do grupo"
|
||||
|
||||
#: models.py:222
|
||||
msgid "group results"
|
||||
msgstr "resultados dos grupos"
|
||||
@@ -0,0 +1,185 @@
|
||||
# Russian translation strings for django-celery-results.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# ILDAR MINNAKHMETOV <ildarworld@gmail.com>, 2021.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2021-11-09 19:16+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: ILDAR MINNAKHMETOV <ildarworld@gmail.com>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"Language: ru\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: django_celery_results/admin.py:38
|
||||
msgid "Parameters"
|
||||
msgstr "Параметры"
|
||||
|
||||
#: django_celery_results/admin.py:45
|
||||
msgid "Result"
|
||||
msgstr "Результаты"
|
||||
|
||||
#: django_celery_results/apps.py:14
|
||||
msgid "Celery Results"
|
||||
msgstr "Результаты Celery"
|
||||
|
||||
#: django_celery_results/models.py:28
|
||||
msgid "Task ID"
|
||||
msgstr "ID Задачи"
|
||||
|
||||
#: django_celery_results/models.py:29
|
||||
msgid "Celery ID for the Task that was run"
|
||||
msgstr "Celery ID задачи"
|
||||
|
||||
#: django_celery_results/models.py:32
|
||||
msgid "Task Name"
|
||||
msgstr "Название задачи"
|
||||
|
||||
#: django_celery_results/models.py:33
|
||||
msgid "Name of the Task which was run"
|
||||
msgstr "Название задачи которая была запущена"
|
||||
|
||||
#: django_celery_results/models.py:36
|
||||
msgid "Task Positional Arguments"
|
||||
msgstr "Аргументы задачи"
|
||||
|
||||
#: django_celery_results/models.py:37
|
||||
msgid "JSON representation of the positional arguments used with the task"
|
||||
msgstr "JSON с позиционными аргументами задачи (*args)"
|
||||
|
||||
#: django_celery_results/models.py:41
|
||||
msgid "Task Named Arguments"
|
||||
msgstr "Именованные аргументы задачи"
|
||||
|
||||
#: django_celery_results/models.py:42
|
||||
msgid "JSON representation of the named arguments used with the task"
|
||||
msgstr "JSON с именованными аргументами задачи (**kwargs)"
|
||||
|
||||
#: django_celery_results/models.py:47
|
||||
msgid "Task State"
|
||||
msgstr "Статус задачи"
|
||||
|
||||
#: django_celery_results/models.py:48
|
||||
msgid "Current state of the task being run"
|
||||
msgstr "Текущий статус запущенной задачи"
|
||||
|
||||
#: django_celery_results/models.py:51
|
||||
msgid "Worker"
|
||||
msgstr "Воркер"
|
||||
|
||||
#: django_celery_results/models.py:51
|
||||
msgid "Worker that executes the task"
|
||||
msgstr "Воркер который выполняет задачу"
|
||||
|
||||
#: django_celery_results/models.py:55 django_celery_results/models.py:186
|
||||
msgid "Result Content Type"
|
||||
msgstr "Тип контента результата"
|
||||
|
||||
#: django_celery_results/models.py:56 django_celery_results/models.py:187
|
||||
msgid "Content type of the result data"
|
||||
msgstr "Тип контента данных результата"
|
||||
|
||||
#: django_celery_results/models.py:59 django_celery_results/models.py:191
|
||||
msgid "Result Encoding"
|
||||
msgstr "Кодировка результата"
|
||||
|
||||
#: django_celery_results/models.py:60 django_celery_results/models.py:192
|
||||
msgid "The encoding used to save the task result data"
|
||||
msgstr "Кодировка использованная для сохранения данных результата"
|
||||
|
||||
#: django_celery_results/models.py:63 django_celery_results/models.py:196
|
||||
msgid "Result Data"
|
||||
msgstr "Данные результата"
|
||||
|
||||
#: django_celery_results/models.py:64 django_celery_results/models.py:197
|
||||
msgid ""
|
||||
"The data returned by the task. Use content_encoding and content_type fields "
|
||||
"to read."
|
||||
msgstr "Данные, которые вернула задача. Используйте content_encoding и content_type для чтения."
|
||||
|
||||
#: django_celery_results/models.py:68 django_celery_results/models.py:176
|
||||
msgid "Created DateTime"
|
||||
msgstr "Дата и время создания"
|
||||
|
||||
#: django_celery_results/models.py:69
|
||||
msgid "Datetime field when the task result was created in UTC"
|
||||
msgstr "Дата и время когда результат был создан (UTC)"
|
||||
|
||||
#: django_celery_results/models.py:72 django_celery_results/models.py:181
|
||||
msgid "Completed DateTime"
|
||||
msgstr "Дата и время завершения"
|
||||
|
||||
#: django_celery_results/models.py:73
|
||||
msgid "Datetime field when the task was completed in UTC"
|
||||
msgstr "Дата и время когда задача была завершена (UTC)"
|
||||
|
||||
#: django_celery_results/models.py:76
|
||||
msgid "Traceback"
|
||||
msgstr "Traceback"
|
||||
|
||||
#: django_celery_results/models.py:77
|
||||
msgid "Text of the traceback if the task generated one"
|
||||
msgstr "Текст traceback, если есть"
|
||||
|
||||
#: django_celery_results/models.py:80
|
||||
msgid "Task Meta Information"
|
||||
msgstr "Метаинформация задачи"
|
||||
|
||||
#: django_celery_results/models.py:81
|
||||
msgid ""
|
||||
"JSON meta information about the task, such as information on child tasks"
|
||||
msgstr ""
|
||||
"JSON мета-информация о задаче, к примеру о дочерних задачах"
|
||||
|
||||
#: django_celery_results/models.py:91
|
||||
msgid "task result"
|
||||
msgstr "результат задачи"
|
||||
|
||||
#: django_celery_results/models.py:92
|
||||
msgid "task results"
|
||||
msgstr "результаты задач"
|
||||
|
||||
#: django_celery_results/models.py:129 django_celery_results/models.py:171
|
||||
msgid "Group ID"
|
||||
msgstr "ID группы"
|
||||
|
||||
#: django_celery_results/models.py:130
|
||||
msgid "Celery ID for the Chord header group"
|
||||
msgstr "Celery ID для заголовка группы"
|
||||
|
||||
#: django_celery_results/models.py:134
|
||||
msgid ""
|
||||
"JSON serialized list of task result tuples. use .group_result() to decode"
|
||||
msgstr ""
|
||||
"JSON-список кортежей результата. Используйте .group_result() для декодирования"
|
||||
|
||||
#: django_celery_results/models.py:140
|
||||
msgid "Starts at len(chord header) and decrements after each task is finished"
|
||||
msgstr "Начинается в len(chord header) и уменьшается после каждого завершенного задания"
|
||||
|
||||
#: django_celery_results/models.py:172
|
||||
msgid "Celery ID for the Group that was run"
|
||||
msgstr "Celery ID для группы которая была запущена"
|
||||
|
||||
#: django_celery_results/models.py:177
|
||||
msgid "Datetime field when the group result was created in UTC"
|
||||
msgstr "Дата и время если результат группы был создан (UTC)"
|
||||
|
||||
#: django_celery_results/models.py:182
|
||||
msgid "Datetime field when the group was completed in UTC"
|
||||
msgstr "Дата и время, когда группа была завершена (UTC)"
|
||||
|
||||
#: django_celery_results/models.py:217
|
||||
msgid "group result"
|
||||
msgstr "результат группы"
|
||||
|
||||
#: django_celery_results/models.py:218
|
||||
msgid "group results"
|
||||
msgstr "результаты групп"
|
||||
@@ -0,0 +1,191 @@
|
||||
# Simplified Chinese translation strings for django-celery-results.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as django-celery-results.
|
||||
# <acwzy@live.com>, 2021.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version:\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2023-03-19 22:23+0800\n"
|
||||
"PO-Revision-Date: 2021-11-20 23:00+0800\n"
|
||||
"Last-Translator: ifmos <acwzy@live.com>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"Language: zh-hans\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: django_celery_results/admin.py:41
|
||||
msgid "Parameters"
|
||||
msgstr "参数"
|
||||
|
||||
#: django_celery_results/admin.py:48
|
||||
msgid "Result"
|
||||
msgstr "结果"
|
||||
|
||||
#: django_celery_results/apps.py:14
|
||||
msgid "Celery Results"
|
||||
msgstr "Celery 结果"
|
||||
|
||||
#: django_celery_results/models.py:28
|
||||
msgid "Task ID"
|
||||
msgstr "任务 ID"
|
||||
|
||||
#: django_celery_results/models.py:29
|
||||
msgid "Celery ID for the Task that was run"
|
||||
msgstr "已运行任务 Celery ID"
|
||||
|
||||
#: django_celery_results/models.py:32
|
||||
msgid "Periodic Task Name"
|
||||
msgstr "周期任务名称"
|
||||
|
||||
#: django_celery_results/models.py:33
|
||||
msgid "Name of the Periodic Task which was run"
|
||||
msgstr "已运行周期任务名称"
|
||||
|
||||
#: django_celery_results/models.py:40
|
||||
msgid "Task Name"
|
||||
msgstr "任务名称"
|
||||
|
||||
#: django_celery_results/models.py:41
|
||||
msgid "Name of the Task which was run"
|
||||
msgstr "已运行任务名称"
|
||||
|
||||
#: django_celery_results/models.py:44
|
||||
msgid "Task Positional Arguments"
|
||||
msgstr "任务位置参数"
|
||||
|
||||
#: django_celery_results/models.py:45
|
||||
msgid "JSON representation of the positional arguments used with the task"
|
||||
msgstr "该任务位置参数的 JSON 字符串"
|
||||
|
||||
#: django_celery_results/models.py:49
|
||||
msgid "Task Named Arguments"
|
||||
msgstr "任务具名参数"
|
||||
|
||||
#: django_celery_results/models.py:50
|
||||
msgid "JSON representation of the named arguments used with the task"
|
||||
msgstr "该任务具名参数的 JSON 字符串"
|
||||
|
||||
#: django_celery_results/models.py:55
|
||||
msgid "Task State"
|
||||
msgstr "任务状态"
|
||||
|
||||
#: django_celery_results/models.py:56
|
||||
msgid "Current state of the task being run"
|
||||
msgstr "运行中任务的当前状态"
|
||||
|
||||
#: django_celery_results/models.py:59
|
||||
msgid "Worker"
|
||||
msgstr "Worker"
|
||||
|
||||
#: django_celery_results/models.py:59
|
||||
msgid "Worker that executes the task"
|
||||
msgstr "执行该任务的 Worker"
|
||||
|
||||
#: django_celery_results/models.py:63 django_celery_results/models.py:200
|
||||
msgid "Result Content Type"
|
||||
msgstr "结果内容类型"
|
||||
|
||||
#: django_celery_results/models.py:64 django_celery_results/models.py:201
|
||||
msgid "Content type of the result data"
|
||||
msgstr "结果数据的内容类型"
|
||||
|
||||
#: django_celery_results/models.py:67 django_celery_results/models.py:205
|
||||
msgid "Result Encoding"
|
||||
msgstr "结果编码格式"
|
||||
|
||||
#: django_celery_results/models.py:68 django_celery_results/models.py:206
|
||||
msgid "The encoding used to save the task result data"
|
||||
msgstr "保存结果数据的编码格式"
|
||||
|
||||
#: django_celery_results/models.py:71 django_celery_results/models.py:210
|
||||
msgid "Result Data"
|
||||
msgstr "结果数据"
|
||||
|
||||
#: django_celery_results/models.py:72 django_celery_results/models.py:211
|
||||
msgid ""
|
||||
"The data returned by the task. Use content_encoding and content_type fields "
|
||||
"to read."
|
||||
msgstr "该任务返回数据,根据 content_encoding 和 content_type 字段读取。"
|
||||
|
||||
#: django_celery_results/models.py:76 django_celery_results/models.py:190
|
||||
msgid "Created DateTime"
|
||||
msgstr "创建时间"
|
||||
|
||||
#: django_celery_results/models.py:77
|
||||
msgid "Datetime field when the task result was created in UTC"
|
||||
msgstr "UTC格式的任务创建时间字段"
|
||||
|
||||
#: django_celery_results/models.py:80 django_celery_results/models.py:195
|
||||
msgid "Completed DateTime"
|
||||
msgstr "完成时间"
|
||||
|
||||
#: django_celery_results/models.py:81
|
||||
msgid "Datetime field when the task was completed in UTC"
|
||||
msgstr "UTC格式的任务完成时间字段"
|
||||
|
||||
#: django_celery_results/models.py:84
|
||||
msgid "Traceback"
|
||||
msgstr "Traceback"
|
||||
|
||||
#: django_celery_results/models.py:85
|
||||
msgid "Text of the traceback if the task generated one"
|
||||
msgstr "任务生成报错时的 traceback 文本"
|
||||
|
||||
#: django_celery_results/models.py:88
|
||||
msgid "Task Meta Information"
|
||||
msgstr "任务元信息"
|
||||
|
||||
#: django_celery_results/models.py:89
|
||||
msgid ""
|
||||
"JSON meta information about the task, such as information on child tasks"
|
||||
msgstr "关于该任务的 JSON 元信息,如子任务的信息"
|
||||
|
||||
#: django_celery_results/models.py:99
|
||||
msgid "task result"
|
||||
msgstr "任务结果"
|
||||
|
||||
#: django_celery_results/models.py:100
|
||||
msgid "task results"
|
||||
msgstr "任务结果"
|
||||
|
||||
#: django_celery_results/models.py:143 django_celery_results/models.py:185
|
||||
msgid "Group ID"
|
||||
msgstr "分组 ID"
|
||||
|
||||
#: django_celery_results/models.py:144
|
||||
msgid "Celery ID for the Chord header group"
|
||||
msgstr "Chord header 分组的 Celery ID"
|
||||
|
||||
#: django_celery_results/models.py:148
|
||||
msgid ""
|
||||
"JSON serialized list of task result tuples. use .group_result() to decode"
|
||||
msgstr "任务结果元组的 JSON 序列化列表。使用 .group_result() 进行解码"
|
||||
|
||||
#: django_celery_results/models.py:154
|
||||
msgid "Starts at len(chord header) and decrements after each task is finished"
|
||||
msgstr "在 len(chord header) 处开始并且会在每个任务结束后递减"
|
||||
|
||||
#: django_celery_results/models.py:186
|
||||
msgid "Celery ID for the Group that was run"
|
||||
msgstr "已运行分组的 Celery ID"
|
||||
|
||||
#: django_celery_results/models.py:191
|
||||
msgid "Datetime field when the group result was created in UTC"
|
||||
msgstr "分组结果创建时的 UTC 格式 datetime 字段"
|
||||
|
||||
#: django_celery_results/models.py:196
|
||||
msgid "Datetime field when the group was completed in UTC"
|
||||
msgstr "分组结果完成时的 UTC 格式 datetime 字段"
|
||||
|
||||
#: django_celery_results/models.py:231
|
||||
msgid "group result"
|
||||
msgstr "分组结果"
|
||||
|
||||
#: django_celery_results/models.py:232
|
||||
msgid "group results"
|
||||
msgstr "分组结果"
|
||||
@@ -0,0 +1,217 @@
|
||||
"""Model managers."""
|
||||
|
||||
import warnings
|
||||
from functools import wraps
|
||||
from itertools import count
|
||||
|
||||
from celery.utils.time import maybe_timedelta
|
||||
from django.conf import settings
|
||||
from django.db import connections, models, router, transaction
|
||||
|
||||
from .utils import now
|
||||
|
||||
W_ISOLATION_REP = """
|
||||
Polling results with transaction isolation level 'repeatable-read'
|
||||
within the same transaction may give outdated results.
|
||||
|
||||
Be sure to commit the transaction for each poll iteration.
|
||||
"""
|
||||
|
||||
|
||||
class TxIsolationWarning(UserWarning):
|
||||
"""Warning emitted if the transaction isolation level is suboptimal."""
|
||||
|
||||
|
||||
def transaction_retry(max_retries=1):
|
||||
"""Decorate a function to retry database operations.
|
||||
|
||||
For functions doing database operations, adding
|
||||
retrying if the operation fails.
|
||||
|
||||
Keyword Arguments:
|
||||
max_retries (int): Maximum number of retries. Default one retry.
|
||||
|
||||
"""
|
||||
def _outer(fun):
|
||||
|
||||
@wraps(fun)
|
||||
def _inner(*args, **kwargs):
|
||||
_max_retries = kwargs.pop('exception_retry_count', max_retries)
|
||||
for retries in count(0):
|
||||
try:
|
||||
return fun(*args, **kwargs)
|
||||
except Exception: # pragma: no cover
|
||||
# Depending on the database backend used we can experience
|
||||
# various exceptions. E.g. psycopg2 raises an exception
|
||||
# if some operation breaks the transaction, so saving
|
||||
# the task result won't be possible until we rollback
|
||||
# the transaction.
|
||||
if retries >= _max_retries:
|
||||
raise
|
||||
return _inner
|
||||
|
||||
return _outer
|
||||
|
||||
|
||||
class ResultManager(models.Manager):
|
||||
"""Generic manager for celery results."""
|
||||
|
||||
def warn_if_repeatable_read(self):
|
||||
if 'mysql' in self.current_engine().lower():
|
||||
cursor = self.connection_for_read().cursor()
|
||||
# MariaDB and MySQL since 8.0 have different transaction isolation
|
||||
# variables: the former has tx_isolation, while the latter has
|
||||
# transaction_isolation
|
||||
if cursor.execute("SHOW VARIABLES WHERE variable_name IN "
|
||||
"('tx_isolation', 'transaction_isolation');"):
|
||||
isolation = cursor.fetchone()[1]
|
||||
if isolation == 'REPEATABLE-READ':
|
||||
warnings.warn(TxIsolationWarning(W_ISOLATION_REP.strip()))
|
||||
|
||||
def connection_for_write(self):
|
||||
return connections[router.db_for_write(self.model)]
|
||||
|
||||
def connection_for_read(self):
|
||||
return connections[self.db]
|
||||
|
||||
def current_engine(self):
|
||||
try:
|
||||
return settings.DATABASES[self.db]['ENGINE']
|
||||
except AttributeError:
|
||||
return settings.DATABASE_ENGINE
|
||||
|
||||
def get_all_expired(self, expires):
|
||||
"""Get all expired results."""
|
||||
return self.filter(date_done__lt=now() - maybe_timedelta(expires))
|
||||
|
||||
def delete_expired(self, expires):
|
||||
"""Delete all expired results."""
|
||||
with transaction.atomic(using=self.db):
|
||||
self.get_all_expired(expires).delete()
|
||||
|
||||
|
||||
class TaskResultManager(ResultManager):
|
||||
"""Manager for :class:`~.models.TaskResult` models."""
|
||||
|
||||
_last_id = None
|
||||
|
||||
def get_task(self, task_id):
|
||||
"""Get result for task by ``task_id``.
|
||||
|
||||
Keyword Arguments:
|
||||
exception_retry_count (int): How many times to retry by
|
||||
transaction rollback on exception. This could
|
||||
happen in a race condition if another worker is trying to
|
||||
create the same task. The default is to retry once.
|
||||
|
||||
"""
|
||||
try:
|
||||
return self.get(task_id=task_id)
|
||||
except self.model.DoesNotExist:
|
||||
if self._last_id == task_id:
|
||||
self.warn_if_repeatable_read()
|
||||
self._last_id = task_id
|
||||
return self.model(task_id=task_id)
|
||||
|
||||
@transaction_retry(max_retries=2)
|
||||
def store_result(self, content_type, content_encoding,
|
||||
task_id, result, status,
|
||||
traceback=None, meta=None,
|
||||
periodic_task_name=None,
|
||||
task_name=None, task_args=None, task_kwargs=None,
|
||||
worker=None, using=None, **kwargs):
|
||||
"""Store the result and status of a task.
|
||||
|
||||
Arguments:
|
||||
content_type (str): Mime-type of result and meta content.
|
||||
content_encoding (str): Type of encoding (e.g. binary/utf-8).
|
||||
task_id (str): Id of task.
|
||||
periodic_task_name (str): Celery Periodic task name.
|
||||
task_name (str): Celery task name.
|
||||
task_args (str): Task arguments.
|
||||
task_kwargs (str): Task kwargs.
|
||||
result (str): The serialized return value of the task,
|
||||
or an exception instance raised by the task.
|
||||
status (str): Task status. See :mod:`celery.states` for a list of
|
||||
possible status values.
|
||||
worker (str): Worker that executes the task.
|
||||
using (str): Django database connection to use.
|
||||
traceback (str): The traceback string taken at the point of
|
||||
exception (only passed if the task failed).
|
||||
meta (str): Serialized result meta data (this contains e.g.
|
||||
children).
|
||||
|
||||
Keyword Arguments:
|
||||
exception_retry_count (int): How many times to retry by
|
||||
transaction rollback on exception. This could
|
||||
happen in a race condition if another worker is trying to
|
||||
create the same task. The default is to retry twice.
|
||||
|
||||
"""
|
||||
fields = {
|
||||
'status': status,
|
||||
'result': result,
|
||||
'traceback': traceback,
|
||||
'meta': meta,
|
||||
'content_encoding': content_encoding,
|
||||
'content_type': content_type,
|
||||
'periodic_task_name': periodic_task_name,
|
||||
'task_name': task_name,
|
||||
'task_args': task_args,
|
||||
'task_kwargs': task_kwargs,
|
||||
'worker': worker
|
||||
}
|
||||
if 'date_started' in kwargs:
|
||||
fields['date_started'] = kwargs['date_started']
|
||||
|
||||
obj, created = self.using(using).get_or_create(task_id=task_id,
|
||||
defaults=fields)
|
||||
if not created:
|
||||
for k, v in fields.items():
|
||||
setattr(obj, k, v)
|
||||
obj.save(using=using)
|
||||
return obj
|
||||
|
||||
|
||||
class GroupResultManager(ResultManager):
|
||||
"""Manager for :class:`~.models.GroupResult` models."""
|
||||
|
||||
_last_id = None
|
||||
|
||||
def get_group(self, group_id):
|
||||
"""Get result for group by ``group_id``.
|
||||
|
||||
Keyword Arguments:
|
||||
exception_retry_count (int): How many times to retry by
|
||||
transaction rollback on exception. This could
|
||||
happen in a race condition if another worker is trying to
|
||||
create the same task. The default is to retry once.
|
||||
|
||||
"""
|
||||
try:
|
||||
return self.get(group_id=group_id)
|
||||
except self.model.DoesNotExist:
|
||||
if self._last_id == group_id:
|
||||
self.warn_if_repeatable_read()
|
||||
self._last_id = group_id
|
||||
return self.model(group_id=group_id)
|
||||
|
||||
@transaction_retry(max_retries=2)
|
||||
def store_group_result(self, content_type, content_encoding,
|
||||
group_id, result, using=None):
|
||||
fields = {
|
||||
'result': result,
|
||||
'content_encoding': content_encoding,
|
||||
'content_type': content_type,
|
||||
}
|
||||
|
||||
if not using:
|
||||
using = self.db
|
||||
|
||||
obj, created = self.using(using).get_or_create(group_id=group_id,
|
||||
defaults=fields)
|
||||
if not created:
|
||||
for k, v in fields.items():
|
||||
setattr(obj, k, v)
|
||||
obj.save(using=self.db)
|
||||
return obj
|
||||
@@ -0,0 +1,59 @@
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='TaskResult',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name='ID')),
|
||||
('task_id', models.CharField(
|
||||
max_length=getattr(
|
||||
settings,
|
||||
'DJANGO_CELERY_RESULTS_TASK_ID_MAX_LENGTH',
|
||||
255
|
||||
),
|
||||
unique=True,
|
||||
verbose_name='task id'
|
||||
)),
|
||||
('status', models.CharField(choices=[('FAILURE', 'FAILURE'),
|
||||
('PENDING', 'PENDING'),
|
||||
('RECEIVED', 'RECEIVED'),
|
||||
('RETRY', 'RETRY'),
|
||||
('REVOKED', 'REVOKED'),
|
||||
('STARTED', 'STARTED'),
|
||||
('SUCCESS', 'SUCCESS')],
|
||||
default='PENDING',
|
||||
max_length=50,
|
||||
verbose_name='state')),
|
||||
('content_type', models.CharField(
|
||||
max_length=128, verbose_name='content type')),
|
||||
('content_encoding', models.CharField(
|
||||
max_length=64, verbose_name='content encoding')),
|
||||
('result', models.TextField(default=None, editable=False,
|
||||
null=True)),
|
||||
('date_done', models.DateTimeField(
|
||||
auto_now=True, verbose_name='done at')),
|
||||
('traceback', models.TextField(
|
||||
blank=True, null=True, verbose_name='traceback')),
|
||||
('hidden', models.BooleanField(
|
||||
db_index=True, default=False, editable=False)),
|
||||
('meta', models.TextField(default=None, editable=False,
|
||||
null=True)),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'task result',
|
||||
'verbose_name_plural': 'task results',
|
||||
},
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,30 @@
|
||||
# Generated by Django 1.9.1 on 2017-10-26 16:06
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('django_celery_results', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='taskresult',
|
||||
name='task_args',
|
||||
field=models.TextField(null=True, verbose_name='task arguments'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='taskresult',
|
||||
name='task_kwargs',
|
||||
field=models.TextField(null=True, verbose_name='task kwargs'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='taskresult',
|
||||
name='task_name',
|
||||
field=models.CharField(max_length=255, null=True,
|
||||
verbose_name='task name'
|
||||
),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,21 @@
|
||||
# Generated by Django 2.1 on 2018-11-06 11:01
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('django_celery_results', '0002_add_task_name_args_kwargs'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='taskresult',
|
||||
options={
|
||||
'ordering': ['-date_done'],
|
||||
'verbose_name': 'task result',
|
||||
'verbose_name_plural': 'task results'
|
||||
},
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,97 @@
|
||||
# Generated by Django 1.11.20 on 2019-05-16 04:12
|
||||
|
||||
# this file is auto-generated so don't do flake8 on it
|
||||
# flake8: noqa
|
||||
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('django_celery_results', '0003_auto_20181106_1101'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='taskresult',
|
||||
name='content_encoding',
|
||||
field=models.CharField(help_text='The encoding used to save the task result data', max_length=64, verbose_name='Result Encoding'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='taskresult',
|
||||
name='content_type',
|
||||
field=models.CharField(help_text='Content type of the result data', max_length=128, verbose_name='Result Content Type'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='taskresult',
|
||||
name='date_done',
|
||||
field=models.DateTimeField(auto_now=True, db_index=True, help_text='Datetime field when the task was completed in UTC', verbose_name='Completed DateTime'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='taskresult',
|
||||
name='hidden',
|
||||
field=models.BooleanField(db_index=True, default=False, editable=False, help_text='Soft Delete flag that can be used instead of full delete', verbose_name='Hidden'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='taskresult',
|
||||
name='meta',
|
||||
field=models.TextField(default=None, editable=False, help_text='JSON meta information about the task, such as information on child tasks', null=True, verbose_name='Task Meta Information'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='taskresult',
|
||||
name='result',
|
||||
field=models.TextField(default=None, editable=False, help_text='The data returned by the task. Use content_encoding and content_type fields to read.', null=True, verbose_name='Result Data'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='taskresult',
|
||||
name='status',
|
||||
field=models.CharField(choices=[('FAILURE', 'FAILURE'), ('PENDING', 'PENDING'), ('RECEIVED', 'RECEIVED'), ('RETRY', 'RETRY'), ('REVOKED', 'REVOKED'), ('STARTED', 'STARTED'), ('SUCCESS', 'SUCCESS')], db_index=True, default='PENDING', help_text='Current state of the task being run', max_length=50, verbose_name='Task State'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='taskresult',
|
||||
name='task_args',
|
||||
field=models.TextField(help_text='JSON representation of the positional arguments used with the task', null=True, verbose_name='Task Positional Arguments'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='taskresult',
|
||||
name='task_id',
|
||||
field=models.CharField(
|
||||
db_index=True,
|
||||
help_text='Celery ID for the Task that was run',
|
||||
max_length=getattr(
|
||||
settings,
|
||||
'DJANGO_CELERY_RESULTS_TASK_ID_MAX_LENGTH',
|
||||
255
|
||||
),
|
||||
unique=True,
|
||||
verbose_name='Task ID'
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='taskresult',
|
||||
name='task_kwargs',
|
||||
field=models.TextField(help_text='JSON representation of the named arguments used with the task', null=True, verbose_name='Task Named Arguments'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='taskresult',
|
||||
name='task_name',
|
||||
field=models.CharField(
|
||||
db_index=True,
|
||||
help_text='Name of the Task which was run',
|
||||
max_length=getattr(
|
||||
settings,
|
||||
'DJANGO_CELERY_RESULTS_TASK_ID_MAX_LENGTH',
|
||||
255
|
||||
),
|
||||
null=True,
|
||||
verbose_name='Task Name'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='taskresult',
|
||||
name='traceback',
|
||||
field=models.TextField(blank=True, help_text='Text of the traceback if the task generated one', null=True, verbose_name='Traceback'),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,25 @@
|
||||
# Generated by Django 1.11.22 on 2019-07-24 15:38
|
||||
|
||||
# this file is auto-generated so don't do flake8 on it
|
||||
# flake8: noqa
|
||||
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('django_celery_results', '0004_auto_20190516_0412'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='taskresult',
|
||||
name='worker',
|
||||
field=models.CharField(db_index=True, default=None,
|
||||
help_text='Worker that executes the task',
|
||||
max_length=100, null=True,
|
||||
verbose_name='Worker'),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,46 @@
|
||||
# Generated by Django 2.2.4 on 2019-08-21 19:53
|
||||
|
||||
# this file is auto-generated so don't do flake8 on it
|
||||
# flake8: noqa
|
||||
|
||||
|
||||
import django.utils.timezone
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
def copy_date_done_to_date_created(apps, schema_editor):
|
||||
TaskResult = apps.get_model('django_celery_results', 'taskresult')
|
||||
db_alias = schema_editor.connection.alias
|
||||
TaskResult.objects.using(db_alias).all().update(
|
||||
date_created=models.F('date_done')
|
||||
)
|
||||
|
||||
|
||||
def reverse_copy_date_done_to_date_created(app, schema_editor):
|
||||
# the reverse of 'copy_date_done_to_date_created' is do nothing
|
||||
# because the 'date_created' will be removed.
|
||||
pass
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('django_celery_results', '0005_taskresult_worker'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='taskresult',
|
||||
name='date_created',
|
||||
field=models.DateTimeField(
|
||||
auto_now_add=True,
|
||||
db_index=True,
|
||||
default=django.utils.timezone.now,
|
||||
help_text='Datetime field when the task result was created in UTC',
|
||||
verbose_name='Created DateTime'
|
||||
),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.RunPython(copy_date_done_to_date_created,
|
||||
reverse_copy_date_done_to_date_created),
|
||||
]
|
||||
@@ -0,0 +1,21 @@
|
||||
# Generated by Django 2.2.6 on 2019-10-27 11:29
|
||||
|
||||
# this file is auto-generated so don't do flake8 on it
|
||||
# flake8: noqa
|
||||
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('django_celery_results', '0006_taskresult_date_created'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='taskresult',
|
||||
name='hidden',
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,40 @@
|
||||
# Generated by Django 3.0.6 on 2020-05-12 12:05
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('django_celery_results', '0007_remove_taskresult_hidden'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='ChordCounter',
|
||||
fields=[
|
||||
('id', models.AutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name='ID')),
|
||||
('group_id', models.CharField(
|
||||
db_index=True,
|
||||
help_text='Celery ID for the Chord header group',
|
||||
max_length=getattr(
|
||||
settings,
|
||||
'DJANGO_CELERY_RESULTS_TASK_ID_MAX_LENGTH',
|
||||
255
|
||||
),
|
||||
unique=True,
|
||||
verbose_name='Group ID')),
|
||||
('sub_tasks', models.TextField(
|
||||
help_text='JSON serialized list of task result tuples. '
|
||||
'use .group_result() to decode')),
|
||||
('count', models.PositiveIntegerField(
|
||||
help_text='Starts at len(chord header) '
|
||||
'and decrements after each task is finished')),
|
||||
],
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,222 @@
|
||||
# Generated by Django 3.2 on 2021-04-19 14:55
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class FakeAddIndex(migrations.AddIndex):
|
||||
"""Fake AddIndex to correct for duplicate index
|
||||
added in the original 0009 migration
|
||||
"""
|
||||
def database_forwards(self, *args, **kwargs):
|
||||
"""Don't do anything"""
|
||||
|
||||
def database_backwards(self, *args, **kwargs):
|
||||
"""Also don't do anything on reverting this migration
|
||||
|
||||
The duplicate index will be cleaned up when migrating from the
|
||||
original 0009 to the cleanup 0010
|
||||
"""
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('django_celery_results', '0008_chordcounter'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='GroupResult',
|
||||
fields=[
|
||||
('id', models.AutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name='ID')),
|
||||
('group_id', models.CharField(
|
||||
help_text='Celery ID for the Group that was run',
|
||||
max_length=getattr(
|
||||
settings,
|
||||
'DJANGO_CELERY_RESULTS_TASK_ID_MAX_LENGTH',
|
||||
255
|
||||
),
|
||||
unique=True,
|
||||
verbose_name='Group ID')),
|
||||
('date_created', models.DateTimeField(
|
||||
auto_now_add=True,
|
||||
help_text='Datetime field when the group result '
|
||||
'was created in UTC',
|
||||
verbose_name='Created DateTime')),
|
||||
('date_done', models.DateTimeField(
|
||||
auto_now=True,
|
||||
help_text='Datetime field when the group was '
|
||||
'completed in UTC',
|
||||
verbose_name='Completed DateTime')),
|
||||
('content_type', models.CharField(
|
||||
help_text='Content type of the result data',
|
||||
max_length=128,
|
||||
verbose_name='Result Content Type')),
|
||||
('content_encoding', models.CharField(
|
||||
help_text='The encoding used to save the task '
|
||||
'result data',
|
||||
max_length=64,
|
||||
verbose_name='Result Encoding')),
|
||||
('result', models.TextField(
|
||||
default=None,
|
||||
editable=False,
|
||||
help_text='The data returned by the task. Use '
|
||||
'content_encoding and content_type '
|
||||
'fields to read.',
|
||||
null=True,
|
||||
verbose_name='Result Data')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'group result',
|
||||
'verbose_name_plural': 'group results',
|
||||
'ordering': ['-date_done'],
|
||||
},
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='chordcounter',
|
||||
name='group_id',
|
||||
field=models.CharField(
|
||||
help_text='Celery ID for the Chord header group',
|
||||
max_length=getattr(
|
||||
settings,
|
||||
'DJANGO_CELERY_RESULTS_TASK_ID_MAX_LENGTH',
|
||||
255
|
||||
),
|
||||
unique=True,
|
||||
verbose_name='Group ID'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='taskresult',
|
||||
name='date_created',
|
||||
field=models.DateTimeField(
|
||||
auto_now_add=True,
|
||||
help_text='Datetime field when the task result '
|
||||
'was created in UTC',
|
||||
verbose_name='Created DateTime'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='taskresult',
|
||||
name='date_done',
|
||||
field=models.DateTimeField(
|
||||
auto_now=True,
|
||||
help_text='Datetime field when the task was completed in UTC',
|
||||
verbose_name='Completed DateTime'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='taskresult',
|
||||
name='status',
|
||||
field=models.CharField(
|
||||
choices=[
|
||||
('FAILURE', 'FAILURE'),
|
||||
('PENDING', 'PENDING'),
|
||||
('RECEIVED', 'RECEIVED'),
|
||||
('RETRY', 'RETRY'),
|
||||
('REVOKED', 'REVOKED'),
|
||||
('STARTED', 'STARTED'),
|
||||
('SUCCESS', 'SUCCESS')],
|
||||
default='PENDING',
|
||||
help_text='Current state of the task being run',
|
||||
max_length=50,
|
||||
verbose_name='Task State'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='taskresult',
|
||||
name='task_id',
|
||||
field=models.CharField(
|
||||
help_text='Celery ID for the Task that was run',
|
||||
max_length=getattr(
|
||||
settings,
|
||||
'DJANGO_CELERY_RESULTS_TASK_ID_MAX_LENGTH',
|
||||
255
|
||||
),
|
||||
unique=True,
|
||||
verbose_name='Task ID'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='taskresult',
|
||||
name='task_name',
|
||||
field=models.CharField(
|
||||
help_text='Name of the Task which was run',
|
||||
max_length=getattr(
|
||||
settings,
|
||||
'DJANGO_CELERY_RESULTS_TASK_ID_MAX_LENGTH',
|
||||
255
|
||||
),
|
||||
null=True,
|
||||
verbose_name='Task Name'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='taskresult',
|
||||
name='worker',
|
||||
field=models.CharField(
|
||||
default=None,
|
||||
help_text='Worker that executes the task',
|
||||
max_length=100,
|
||||
null=True,
|
||||
verbose_name='Worker'),
|
||||
),
|
||||
FakeAddIndex(
|
||||
model_name='chordcounter',
|
||||
index=models.Index(
|
||||
fields=['group_id'],
|
||||
name='django_cele_group_i_299b0d_idx'),
|
||||
),
|
||||
FakeAddIndex(
|
||||
model_name='taskresult',
|
||||
index=models.Index(
|
||||
fields=['task_id'],
|
||||
name='django_cele_task_id_7f8fca_idx'),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='taskresult',
|
||||
index=models.Index(
|
||||
fields=['task_name'],
|
||||
name='django_cele_task_na_08aec9_idx'),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='taskresult',
|
||||
index=models.Index(
|
||||
fields=['status'],
|
||||
name='django_cele_status_9b6201_idx'),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='taskresult',
|
||||
index=models.Index(
|
||||
fields=['worker'],
|
||||
name='django_cele_worker_d54dd8_idx'),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='taskresult',
|
||||
index=models.Index(
|
||||
fields=['date_created'],
|
||||
name='django_cele_date_cr_f04a50_idx'),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='taskresult',
|
||||
index=models.Index(
|
||||
fields=['date_done'],
|
||||
name='django_cele_date_do_f59aad_idx'),
|
||||
),
|
||||
FakeAddIndex(
|
||||
model_name='groupresult',
|
||||
index=models.Index(
|
||||
fields=['group_id'],
|
||||
name='django_cele_group_i_3cddec_idx'),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='groupresult',
|
||||
index=models.Index(
|
||||
fields=['date_created'],
|
||||
name='django_cele_date_cr_bd6c1d_idx'),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='groupresult',
|
||||
index=models.Index(
|
||||
fields=['date_done'],
|
||||
name='django_cele_date_do_caae0e_idx'),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,53 @@
|
||||
"""
|
||||
Migration to amend the 0009 migration released on django_celery_results 2.1.0
|
||||
|
||||
That migration introduced duplicate indexes breaking Oracle support.
|
||||
This migration will remove those indexes (on non-Oracle db's)
|
||||
while in-place changing migration 0009
|
||||
to not add the duplicates for new installs
|
||||
"""
|
||||
|
||||
from django.db import DatabaseError, migrations
|
||||
|
||||
|
||||
class TryRemoveIndex(migrations.RemoveIndex):
|
||||
"""Operation to remove the Index
|
||||
without reintroducing it on reverting the migration
|
||||
"""
|
||||
|
||||
def database_forwards(self, *args, **kwargs):
|
||||
"""Remove the index on the database if it exists"""
|
||||
try:
|
||||
super().database_forwards(*args, **kwargs)
|
||||
except DatabaseError:
|
||||
pass
|
||||
except Exception:
|
||||
# Not all DB engines throw DatabaseError when the
|
||||
# index does not exist.
|
||||
pass
|
||||
|
||||
def database_backwards(self, *args, **kwargs):
|
||||
"""Don't re-add the index when reverting this migration"""
|
||||
pass
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('django_celery_results', '0009_groupresult'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
TryRemoveIndex(
|
||||
model_name='chordcounter',
|
||||
name='django_cele_group_i_299b0d_idx',
|
||||
),
|
||||
TryRemoveIndex(
|
||||
model_name='groupresult',
|
||||
name='django_cele_group_i_3cddec_idx',
|
||||
),
|
||||
TryRemoveIndex(
|
||||
model_name='taskresult',
|
||||
name='django_cele_task_id_7f8fca_idx',
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,22 @@
|
||||
# Generated by Django 3.2.8 on 2021-11-10 08:05
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('django_celery_results', '0010_remove_duplicate_indices'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='taskresult',
|
||||
name='periodic_task_name',
|
||||
field=models.CharField(
|
||||
help_text='Name of the Periodic Task which was run',
|
||||
max_length=255,
|
||||
null=True,
|
||||
verbose_name='Periodic Task Name'),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,23 @@
|
||||
# Generated by Django 4.2.13 on 2024-06-02 07:56
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('django_celery_results', '0011_taskresult_periodic_task_name'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='taskresult',
|
||||
name='date_started',
|
||||
field=models.DateTimeField(
|
||||
default=None,
|
||||
help_text='Datetime field when the task was started in UTC',
|
||||
null=True,
|
||||
verbose_name='Started DateTime',
|
||||
),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,20 @@
|
||||
# Generated by Django 5.1.3 on 2024-11-05 13:17
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('django_celery_results', '0012_taskresult_date_started'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddIndex(
|
||||
model_name='taskresult',
|
||||
index=models.Index(
|
||||
fields=['periodic_task_name'],
|
||||
name='django_cele_periodi_1993cf_idx'
|
||||
),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,26 @@
|
||||
# Generated by Django 5.1.7 on 2025-03-08 06:18
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
(
|
||||
"django_celery_results",
|
||||
"0013_taskresult_django_cele_periodi_1993cf_idx"
|
||||
),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="taskresult",
|
||||
name="status",
|
||||
field=models.CharField(
|
||||
default="PENDING",
|
||||
help_text="Current state of the task being run",
|
||||
max_length=50,
|
||||
verbose_name="Task State",
|
||||
),
|
||||
),
|
||||
]
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,245 @@
|
||||
"""Database models."""
|
||||
|
||||
import json
|
||||
|
||||
from celery import states
|
||||
from celery.result import GroupResult as CeleryGroupResult
|
||||
from celery.result import result_from_tuple
|
||||
from django.conf import settings
|
||||
from django.db import models
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from . import managers
|
||||
|
||||
ALL_STATES = sorted(states.ALL_STATES)
|
||||
TASK_STATE_CHOICES = sorted(zip(ALL_STATES, ALL_STATES))
|
||||
|
||||
|
||||
class TaskResult(models.Model):
|
||||
"""Task result/status."""
|
||||
|
||||
task_id = models.CharField(
|
||||
max_length=getattr(
|
||||
settings,
|
||||
'DJANGO_CELERY_RESULTS_TASK_ID_MAX_LENGTH',
|
||||
255
|
||||
),
|
||||
unique=True,
|
||||
verbose_name=_('Task ID'),
|
||||
help_text=_('Celery ID for the Task that was run'))
|
||||
periodic_task_name = models.CharField(
|
||||
null=True, max_length=255,
|
||||
verbose_name=_('Periodic Task Name'),
|
||||
help_text=_('Name of the Periodic Task which was run'))
|
||||
task_name = models.CharField(
|
||||
null=True, max_length=getattr(
|
||||
settings,
|
||||
'DJANGO_CELERY_RESULTS_TASK_ID_MAX_LENGTH',
|
||||
255
|
||||
),
|
||||
verbose_name=_('Task Name'),
|
||||
help_text=_('Name of the Task which was run'))
|
||||
task_args = models.TextField(
|
||||
null=True,
|
||||
verbose_name=_('Task Positional Arguments'),
|
||||
help_text=_('JSON representation of the positional arguments '
|
||||
'used with the task'))
|
||||
task_kwargs = models.TextField(
|
||||
null=True,
|
||||
verbose_name=_('Task Named Arguments'),
|
||||
help_text=_('JSON representation of the named arguments '
|
||||
'used with the task'))
|
||||
status = models.CharField(
|
||||
max_length=50, default=states.PENDING,
|
||||
verbose_name=_('Task State'),
|
||||
help_text=_('Current state of the task being run'))
|
||||
worker = models.CharField(
|
||||
max_length=100, default=None, null=True,
|
||||
verbose_name=_('Worker'), help_text=_('Worker that executes the task')
|
||||
)
|
||||
content_type = models.CharField(
|
||||
max_length=128,
|
||||
verbose_name=_('Result Content Type'),
|
||||
help_text=_('Content type of the result data'))
|
||||
content_encoding = models.CharField(
|
||||
max_length=64,
|
||||
verbose_name=_('Result Encoding'),
|
||||
help_text=_('The encoding used to save the task result data'))
|
||||
result = models.TextField(
|
||||
null=True, default=None, editable=False,
|
||||
verbose_name=_('Result Data'),
|
||||
help_text=_('The data returned by the task. '
|
||||
'Use content_encoding and content_type fields to read.'))
|
||||
date_created = models.DateTimeField(
|
||||
auto_now_add=True,
|
||||
verbose_name=_('Created DateTime'),
|
||||
help_text=_('Datetime field when the task result was created in UTC'))
|
||||
date_started = models.DateTimeField(
|
||||
null=True, default=None,
|
||||
verbose_name=_('Started DateTime'),
|
||||
help_text=_('Datetime field when the task was started in UTC'))
|
||||
date_done = models.DateTimeField(
|
||||
auto_now=True,
|
||||
verbose_name=_('Completed DateTime'),
|
||||
help_text=_('Datetime field when the task was completed in UTC'))
|
||||
traceback = models.TextField(
|
||||
blank=True, null=True,
|
||||
verbose_name=_('Traceback'),
|
||||
help_text=_('Text of the traceback if the task generated one'))
|
||||
meta = models.TextField(
|
||||
null=True, default=None, editable=False,
|
||||
verbose_name=_('Task Meta Information'),
|
||||
help_text=_('JSON meta information about the task, '
|
||||
'such as information on child tasks'))
|
||||
|
||||
objects = managers.TaskResultManager()
|
||||
|
||||
class Meta:
|
||||
"""Table information."""
|
||||
|
||||
ordering = ['-date_done']
|
||||
|
||||
verbose_name = _('task result')
|
||||
verbose_name_plural = _('task results')
|
||||
|
||||
# Explicit names to solve https://code.djangoproject.com/ticket/33483
|
||||
indexes = [
|
||||
models.Index(fields=['task_name'],
|
||||
name='django_cele_task_na_08aec9_idx'),
|
||||
models.Index(fields=['status'],
|
||||
name='django_cele_status_9b6201_idx'),
|
||||
models.Index(fields=['worker'],
|
||||
name='django_cele_worker_d54dd8_idx'),
|
||||
models.Index(fields=['date_created'],
|
||||
name='django_cele_date_cr_f04a50_idx'),
|
||||
models.Index(fields=['date_done'],
|
||||
name='django_cele_date_do_f59aad_idx'),
|
||||
models.Index(fields=['periodic_task_name'],
|
||||
name='django_cele_periodi_1993cf_idx'),
|
||||
]
|
||||
|
||||
def as_dict(self):
|
||||
return {
|
||||
'task_id': self.task_id,
|
||||
'task_name': self.task_name,
|
||||
'task_args': self.task_args,
|
||||
'task_kwargs': self.task_kwargs,
|
||||
'status': self.status,
|
||||
'result': self.result,
|
||||
'date_done': self.date_done,
|
||||
'traceback': self.traceback,
|
||||
'meta': self.meta,
|
||||
'worker': self.worker
|
||||
}
|
||||
|
||||
def __str__(self):
|
||||
return '<Task: {0.task_id} ({0.status})>'.format(self)
|
||||
|
||||
|
||||
class ChordCounter(models.Model):
|
||||
"""Chord synchronisation."""
|
||||
|
||||
group_id = models.CharField(
|
||||
max_length=getattr(
|
||||
settings,
|
||||
"DJANGO_CELERY_RESULTS_TASK_ID_MAX_LENGTH",
|
||||
255),
|
||||
unique=True,
|
||||
verbose_name=_("Group ID"),
|
||||
help_text=_("Celery ID for the Chord header group"),
|
||||
)
|
||||
sub_tasks = models.TextField(
|
||||
help_text=_(
|
||||
"JSON serialized list of task result tuples. "
|
||||
"use .group_result() to decode"
|
||||
)
|
||||
)
|
||||
count = models.PositiveIntegerField(
|
||||
help_text=_(
|
||||
"Starts at len(chord header) and decrements after each task is "
|
||||
"finished"
|
||||
)
|
||||
)
|
||||
|
||||
def group_result(self, app=None):
|
||||
"""Return the :class:`celery.result.GroupResult` of self.
|
||||
|
||||
Arguments:
|
||||
app (celery.app.base.Celery): app instance to create the
|
||||
:class:`celery.result.GroupResult` with.
|
||||
|
||||
"""
|
||||
return CeleryGroupResult(
|
||||
self.group_id,
|
||||
[result_from_tuple(r, app=app)
|
||||
for r in json.loads(self.sub_tasks)],
|
||||
app=app
|
||||
)
|
||||
|
||||
|
||||
class GroupResult(models.Model):
|
||||
"""Task Group result/status."""
|
||||
|
||||
group_id = models.CharField(
|
||||
max_length=getattr(
|
||||
settings,
|
||||
"DJANGO_CELERY_RESULTS_TASK_ID_MAX_LENGTH",
|
||||
255
|
||||
),
|
||||
unique=True,
|
||||
verbose_name=_("Group ID"),
|
||||
help_text=_("Celery ID for the Group that was run"),
|
||||
)
|
||||
date_created = models.DateTimeField(
|
||||
auto_now_add=True,
|
||||
verbose_name=_("Created DateTime"),
|
||||
help_text=_("Datetime field when the group result was created in UTC"),
|
||||
)
|
||||
date_done = models.DateTimeField(
|
||||
auto_now=True,
|
||||
verbose_name=_("Completed DateTime"),
|
||||
help_text=_("Datetime field when the group was completed in UTC"),
|
||||
)
|
||||
content_type = models.CharField(
|
||||
max_length=128,
|
||||
verbose_name=_("Result Content Type"),
|
||||
help_text=_("Content type of the result data"),
|
||||
)
|
||||
content_encoding = models.CharField(
|
||||
max_length=64,
|
||||
verbose_name=_("Result Encoding"),
|
||||
help_text=_("The encoding used to save the task result data"),
|
||||
)
|
||||
result = models.TextField(
|
||||
null=True, default=None, editable=False,
|
||||
verbose_name=_('Result Data'),
|
||||
help_text=_('The data returned by the task. '
|
||||
'Use content_encoding and content_type fields to read.'))
|
||||
|
||||
def as_dict(self):
|
||||
return {
|
||||
'group_id': self.group_id,
|
||||
'result': self.result,
|
||||
'date_done': self.date_done,
|
||||
}
|
||||
|
||||
def __str__(self):
|
||||
return f'<Group: {self.group_id}>'
|
||||
|
||||
objects = managers.GroupResultManager()
|
||||
|
||||
class Meta:
|
||||
"""Table information."""
|
||||
|
||||
ordering = ['-date_done']
|
||||
|
||||
verbose_name = _('group result')
|
||||
verbose_name_plural = _('group results')
|
||||
|
||||
# Explicit names to solve https://code.djangoproject.com/ticket/33483
|
||||
indexes = [
|
||||
models.Index(fields=['date_created'],
|
||||
name='django_cele_date_cr_bd6c1d_idx'),
|
||||
models.Index(fields=['date_done'],
|
||||
name='django_cele_date_do_caae0e_idx'),
|
||||
]
|
||||
@@ -0,0 +1,86 @@
|
||||
"""URLs defined for celery.
|
||||
|
||||
* ``/$task_id/done/``
|
||||
URL to :func:`~celery.views.is_successful`.
|
||||
* ``/$task_id/status/``
|
||||
URL to :func:`~celery.views.task_status`.
|
||||
"""
|
||||
import warnings
|
||||
|
||||
from django.conf import settings
|
||||
from django.urls import path, register_converter
|
||||
|
||||
from . import views
|
||||
|
||||
|
||||
class TaskPatternConverter:
|
||||
"""Custom path converter for task & group id's.
|
||||
|
||||
They are slightly different from the built `uuid`
|
||||
"""
|
||||
|
||||
regex = r'[\w\d\-\.]+'
|
||||
|
||||
def to_python(self, value):
|
||||
"""Convert url to python value."""
|
||||
return str(value)
|
||||
|
||||
def to_url(self, value):
|
||||
"""Convert python value into url, just a string."""
|
||||
return value
|
||||
|
||||
|
||||
register_converter(TaskPatternConverter, 'task_pattern')
|
||||
|
||||
urlpatterns = [
|
||||
path(
|
||||
'task/done/<task_pattern:task_id>/',
|
||||
views.is_task_successful,
|
||||
name='celery-is_task_successful'
|
||||
),
|
||||
path(
|
||||
'task/status/<task_pattern:task_id>/',
|
||||
views.task_status,
|
||||
name='celery-task_status'
|
||||
),
|
||||
path(
|
||||
'group/done/<task_pattern:group_id>/',
|
||||
views.is_group_successful,
|
||||
name='celery-is_group_successful'
|
||||
),
|
||||
path(
|
||||
'group/status/<task_pattern:group_id>/',
|
||||
views.group_status,
|
||||
name='celery-group_status'
|
||||
),
|
||||
]
|
||||
|
||||
if getattr(settings, 'DJANGO_CELERY_RESULTS_ID_FIRST_URLS', True):
|
||||
warnings.warn(
|
||||
"ID first urls depricated, use noun first urls instead."
|
||||
"Will be removed in 2022.",
|
||||
DeprecationWarning
|
||||
)
|
||||
|
||||
urlpatterns += [
|
||||
path(
|
||||
'<task_pattern:task_id>/done/',
|
||||
views.is_task_successful,
|
||||
name='celery-is_task_successful'
|
||||
),
|
||||
path(
|
||||
'<task_pattern:task_id>/status/',
|
||||
views.task_status,
|
||||
name='celery-task_status'
|
||||
),
|
||||
path(
|
||||
'<task_pattern:group_id>/group/done/',
|
||||
views.is_group_successful,
|
||||
name='celery-is_group_successful'
|
||||
),
|
||||
path(
|
||||
'<task_pattern:group_id>/group/status/',
|
||||
views.group_status,
|
||||
name='celery-group_status'
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,17 @@
|
||||
"""Utilities."""
|
||||
# -- XXX This module must not use translation as that causes
|
||||
# -- a recursive loader import!
|
||||
|
||||
from django.conf import settings
|
||||
from django.utils import timezone
|
||||
|
||||
# see Issue celery/django-celery#222
|
||||
now_localtime = getattr(timezone, 'template_localtime', timezone.localtime)
|
||||
|
||||
|
||||
def now():
|
||||
"""Return the current date and time."""
|
||||
if getattr(settings, 'USE_TZ', False):
|
||||
return now_localtime(timezone.now())
|
||||
else:
|
||||
return timezone.now()
|
||||
@@ -0,0 +1,53 @@
|
||||
"""Views."""
|
||||
from celery import states
|
||||
from celery.result import AsyncResult, GroupResult
|
||||
from celery.utils import get_full_cls_name
|
||||
from django.http import JsonResponse
|
||||
from kombu.utils.encoding import safe_repr
|
||||
|
||||
|
||||
def is_task_successful(request, task_id):
|
||||
"""Return task execution status in JSON format."""
|
||||
return JsonResponse({'task': {
|
||||
'id': task_id,
|
||||
'executed': AsyncResult(task_id).successful(),
|
||||
}})
|
||||
|
||||
|
||||
def task_status(request, task_id):
|
||||
"""Return task status and result in JSON format."""
|
||||
result = AsyncResult(task_id)
|
||||
state, retval = result.state, result.result
|
||||
response_data = {'id': task_id, 'status': state, 'result': retval}
|
||||
if state in states.EXCEPTION_STATES:
|
||||
traceback = result.traceback
|
||||
response_data.update({'result': safe_repr(retval),
|
||||
'exc': get_full_cls_name(retval.__class__),
|
||||
'traceback': traceback})
|
||||
return JsonResponse({'task': response_data})
|
||||
|
||||
|
||||
def is_group_successful(request, group_id):
|
||||
"""Return if group was successfull as boolean."""
|
||||
results = GroupResult.restore(group_id)
|
||||
|
||||
return JsonResponse({
|
||||
'group': {
|
||||
'id': group_id,
|
||||
'results': [
|
||||
{'id': task.id, 'executed': task.successful()}
|
||||
for task in results
|
||||
] if results else []
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
def group_status(request, group_id):
|
||||
"""Return group id and its async results status & result in JSON format."""
|
||||
result = GroupResult.restore(group_id)
|
||||
retval = [
|
||||
{"result": async_result.result, "status": async_result.status}
|
||||
for async_result in result.results
|
||||
]
|
||||
response_data = {'id': group_id, 'results': retval}
|
||||
return JsonResponse({'group': response_data})
|
||||
Reference in New Issue
Block a user