asynchronous refactoring
- don't execute celery tasks directly - introduce optional parameters to fileserver tasks to allow chaining - handle user/group/key create and delete tasks in new osusers.signals class - adapt unit tests - change TaskResults model to store the task signatures - generalize the local settings' logging configuration
This commit is contained in:
parent
bcfea10e6f
commit
d5bba7a22d
12 changed files with 290 additions and 170 deletions
|
@ -0,0 +1,36 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('taskresults', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='taskresult',
|
||||
name='task_name',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='taskresult',
|
||||
name='creator',
|
||||
field=models.TextField(default='migrated', verbose_name='Task creator'),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='taskresult',
|
||||
name='notes',
|
||||
field=models.TextField(default='', verbose_name='Task notes'),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='taskresult',
|
||||
name='signature',
|
||||
field=models.TextField(default='', verbose_name='Task signature'),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
|
@ -12,15 +12,21 @@ from gnuviechadmin.celery import app
|
|||
|
||||
|
||||
class TaskResultManager(models.Manager):
|
||||
def create_task_result(self, asyncresult, name):
|
||||
taskresult = self.create(task_id=asyncresult.id, task_name=name)
|
||||
def create_task_result(self, creator, signature, notes=''):
|
||||
sigstr = str(signature)
|
||||
result = signature.apply_async()
|
||||
taskresult = self.create(
|
||||
task_id=result.task_id, creator=creator, signature=sigstr,
|
||||
notes=notes)
|
||||
return taskresult
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class TaskResult(models.Model):
|
||||
task_id = models.CharField(_('Task id'), max_length=36)
|
||||
task_name = models.CharField(_('Task name'), max_length=64)
|
||||
signature = models.TextField(_('Task signature'))
|
||||
creator = models.TextField(_('Task creator'))
|
||||
notes = models.TextField(_('Task notes'))
|
||||
result = models.TextField(_('Task result'))
|
||||
finished = models.BooleanField(default=False)
|
||||
state = models.CharField(_('Task state'), max_length=16)
|
||||
|
@ -32,8 +38,8 @@ class TaskResult(models.Model):
|
|||
verbose_name_plural = _('Task results')
|
||||
|
||||
def __str__(self):
|
||||
return "{task_name} ({task_id}): {finished}".format(
|
||||
task_name=self.task_name,
|
||||
return "{creator} ({task_id}): {finished}".format(
|
||||
creator=self.creator,
|
||||
task_id=self.task_id,
|
||||
finished=_('yes') if self.finished else _('no')
|
||||
)
|
||||
|
@ -41,7 +47,8 @@ class TaskResult(models.Model):
|
|||
def fetch_result(self):
|
||||
if not self.finished:
|
||||
ar = app.AsyncResult(self.task_id)
|
||||
res = ar.get(no_ack=True, timeout=1)
|
||||
self.result = str(res)
|
||||
self.state = ar.state
|
||||
self.finished = True
|
||||
if ar.ready():
|
||||
res = ar.get()
|
||||
self.result = str(res)
|
||||
self.finished = True
|
||||
|
|
|
@ -13,24 +13,30 @@ TEST_TASK_RESULT = '4ll y0ur b453 4r3 b3l0ng t0 u5'
|
|||
class TaskResultTest(TestCase):
|
||||
@patch('taskresults.models.app')
|
||||
def test_update_taskstatus_unfinished(self, app):
|
||||
mock = MagicMock(id=TEST_TASK_UUID, task_name=TEST_TASK_NAME)
|
||||
mock.ready.return_value = False
|
||||
tr = TaskResult.objects.create_task_result(mock, TEST_TASK_NAME)
|
||||
resultmock = MagicMock(task_id=TEST_TASK_UUID)
|
||||
resultmock.ready.return_value = False
|
||||
mock = MagicMock()
|
||||
mock.apply_async.return_value = resultmock
|
||||
tr = TaskResult.objects.create_task_result(TEST_TASK_NAME, mock)
|
||||
self.assertFalse(tr.finished)
|
||||
mymock = app.AsyncResult(TEST_TASK_UUID)
|
||||
mymock.state = 'SUCCESS'
|
||||
mymock.get.return_value = TEST_RESULT
|
||||
tr.fetch_result()
|
||||
mymock.get.assert_called_with(no_ack=True, timeout=1)
|
||||
mymock.get.assert_called_with()
|
||||
self.assertTrue(tr.finished)
|
||||
|
||||
@patch('taskresults.models.app')
|
||||
def test_update_taskstatus_finished(self, app):
|
||||
mock = MagicMock(id=TEST_TASK_UUID, task_name=TEST_TASK_NAME)
|
||||
mock.ready.return_value = True
|
||||
resultmock = MagicMock(task_id=TEST_TASK_UUID)
|
||||
resultmock.ready.return_value = True
|
||||
resultmock.state = 'SUCCESS'
|
||||
resultmock.result = TEST_RESULT
|
||||
mock = MagicMock()
|
||||
mock.apply_async.return_value = resultmock
|
||||
mock.state = 'SUCCESS'
|
||||
mock.result = TEST_RESULT
|
||||
tr = TaskResult.objects.create_task_result(mock, TEST_TASK_NAME)
|
||||
tr = TaskResult.objects.create_task_result(TEST_TASK_NAME, mock)
|
||||
tr.fetch_result()
|
||||
self.assertTrue(tr.finished)
|
||||
mymock = app.AsyncResult(TEST_TASK_UUID)
|
||||
|
@ -47,8 +53,10 @@ TEST_RESULT.ready.return_value = False
|
|||
|
||||
class TaskResultManagerTest(TestCase):
|
||||
def test_create_task_result(self):
|
||||
mock = MagicMock(id=TEST_TASK_UUID)
|
||||
tr = TaskResult.objects.create_task_result(mock, TEST_TASK_NAME)
|
||||
resultmock = MagicMock(task_id=TEST_TASK_UUID)
|
||||
mock = MagicMock()
|
||||
mock.apply_async.return_value = resultmock
|
||||
tr = TaskResult.objects.create_task_result(TEST_TASK_NAME, mock)
|
||||
self.assertIsInstance(tr, TaskResult)
|
||||
self.assertEqual(tr.task_id, TEST_TASK_UUID)
|
||||
self.assertEqual(tr.task_name, TEST_TASK_NAME)
|
||||
self.assertEqual(tr.creator, TEST_TASK_NAME)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue