def test_updates_task_status_correctly(self, mock_request): exc = Exception() task_id = str(uuid.uuid4()) args = [1, 'b', 'iii'] kwargs = {'1': 'for the money', 'tags': ['test_tags']} class EInfo(object): """ on_failure handler expects an instance of celery's ExceptionInfo class as one of the attributes. It stores string representation of traceback in it's traceback instance variable. This is a stub to imitate that behavior. """ def __init__(self): self.traceback = "string_repr_of_traceback" einfo = EInfo() mock_request.called_directly = False task_status = TaskStatusManager.create_task_status(task_id) self.assertEqual(task_status['state'], 'waiting') self.assertEqual(task_status['finish_time'], None) self.assertEqual(task_status['traceback'], None) task = tasks.Task() task.on_failure(exc, task_id, args, kwargs, einfo) new_task_status = TaskStatusManager.find_by_task_id(task_id) self.assertEqual(new_task_status['state'], 'error') self.assertFalse(new_task_status['finish_time'] is None) # Make sure that parse_iso8601_datetime is able to parse the finish_time without errors dateutils.parse_iso8601_datetime(new_task_status['finish_time']) self.assertEqual(new_task_status['traceback'], einfo.traceback)
def test_update_task_status(self): """ Tests the successful operation of update_task_status(). """ task_id = self.get_random_uuid() queue = 'special_queue' tags = ['test-tag1', 'test-tag2'] state = 'waiting' TaskStatusManager.create_task_status(task_id, queue, tags, state) now = datetime.now(dateutils.utc_tz()) start_time = dateutils.format_iso8601_datetime(now) delta = {'start_time': start_time, 'state': 'running', 'disregard': 'ignored', 'progress_report': {'report-id': 'my-progress'}} updated = TaskStatusManager.update_task_status(task_id, delta) task_status = TaskStatusManager.find_by_task_id(task_id) self.assertEqual(task_status['start_time'], delta['start_time']) # Make sure that parse_iso8601_datetime is able to parse the start_time without errors dateutils.parse_iso8601_datetime(task_status['start_time']) self.assertEqual(task_status['state'], delta['state']) self.assertEqual(task_status['progress_report'], delta['progress_report']) self.assertEqual(task_status['queue'], queue) self.assertEqual(updated['start_time'], delta['start_time']) self.assertEqual(updated['state'], delta['state']) self.assertEqual(updated['progress_report'], delta['progress_report']) self.assertTrue('disregard' not in updated) self.assertTrue('disregard' not in task_status)
def test_spawned_task_status(self, mock_request): async_result = AsyncResult('foo-id') retval = tasks.TaskResult(error=PulpException('error-foo'), result='bar') retval.spawned_tasks = [async_result] task_id = str(uuid.uuid4()) args = [1, 'b', 'iii'] kwargs = {'1': 'for the money', 'tags': ['test_tags'], 'routing_key': WORKER_2} mock_request.called_directly = False task_status = TaskStatusManager.create_task_status(task_id) self.assertEqual(task_status['state'], 'waiting') self.assertEqual(task_status['finish_time'], None) task = tasks.Task() task.on_success(retval, task_id, args, kwargs) new_task_status = TaskStatusManager.find_by_task_id(task_id) self.assertEqual(new_task_status['state'], 'finished') self.assertEqual(new_task_status['result'], 'bar') self.assertEqual(new_task_status['error']['description'], 'error-foo') self.assertFalse(new_task_status['finish_time'] is None) # Make sure that parse_iso8601_datetime is able to parse the finish_time without errors dateutils.parse_iso8601_datetime(new_task_status['finish_time']) self.assertEqual(new_task_status['spawned_tasks'], ['foo-id'])
def test_on_failure_handler(self, mock_request): """ Make sure that overridden on_failure handler updates task status correctly """ exc = Exception() task_id = str(uuid.uuid4()) args = [1, 'b', 'iii'] kwargs = {'1': 'for the money', 'tags': ['test_tags']} class EInfo(object): """ on_failure handler expects an instance of celery's ExceptionInfo class as one of the attributes. It stores string representation of traceback in it's traceback instance variable. This is a stub to imitate that behavior. """ def __init__(self): self.traceback = "string_repr_of_traceback" einfo = EInfo() mock_request.called_directly = False task_status = TaskStatusManager.create_task_status(task_id, 'some_queue') self.assertEqual(task_status['state'], 'waiting') self.assertEqual(task_status['finish_time'], None) self.assertEqual(task_status['traceback'], None) task = tasks.Task() task.on_failure(exc, task_id, args, kwargs, einfo) new_task_status = TaskStatusManager.find_by_task_id(task_id) self.assertEqual(new_task_status['state'], 'error') self.assertFalse(new_task_status['finish_time'] is None) # Make sure that parse_iso8601_datetime is able to parse the finish_time without errors dateutils.parse_iso8601_datetime(new_task_status['finish_time']) self.assertEqual(new_task_status['traceback'], einfo.traceback)
def test_on_success_handler_async_result(self, mock_request): """ Make sure that overridden on_success handler updates task status correctly """ retval = AsyncResult('foo-id') task_id = str(uuid.uuid4()) args = [1, 'b', 'iii'] kwargs = {'1': 'for the money', 'tags': ['test_tags'], 'queue': RESERVED_WORKER_2} mock_request.called_directly = False task_status = TaskStatusManager.create_task_status(task_id, 'some_queue') self.assertEqual(task_status['state'], 'waiting') self.assertEqual(task_status['finish_time'], None) task = tasks.Task() task.on_success(retval, task_id, args, kwargs) new_task_status = TaskStatusManager.find_by_task_id(task_id) self.assertEqual(new_task_status['state'], 'finished') self.assertEqual(new_task_status['result'], None) self.assertFalse(new_task_status['finish_time'] is None) # Make sure that parse_iso8601_datetime is able to parse the finish_time without errors dateutils.parse_iso8601_datetime(new_task_status['finish_time']) self.assertEqual(new_task_status['spawned_tasks'], ['foo-id'])
def cancel(task_id): """ Cancel the task that is represented by the given task_id. This method cancels only the task with given task_id, not the spawned tasks. This also updates task's state to 'canceled'. :param task_id: The ID of the task you wish to cancel :type task_id: basestring :raises MissingResource: if a task with given task_id does not exist :raises PulpCodedException: if given task is already in a complete state """ task_status = TaskStatusManager.find_by_task_id(task_id) if task_status is None: raise MissingResource(task_id) if task_status['state'] in constants.CALL_COMPLETE_STATES: # If the task is already done, just stop msg = _('Task [%(task_id)s] already in a completed state: %(state)s') logger.info(msg % {'task_id': task_id, 'state': task_status['state']}) return controller.revoke(task_id, terminate=True) TaskStatus.get_collection().find_and_modify( {'task_id': task_id, 'state': {'$nin': constants.CALL_COMPLETE_STATES}}, {'$set': {'state': constants.CALL_CANCELED_STATE}}) msg = _('Task canceled: %(task_id)s.') msg = msg % {'task_id': task_id} logger.info(msg)
def test_update_task_status(self): """ Tests the successful operation of update_task_status(). """ task_id = self.get_random_uuid() queue = 'special_queue' tags = ['test-tag1', 'test-tag2'] state = 'waiting' TaskStatusManager.create_task_status(task_id, queue, tags, state) now = datetime.now(dateutils.utc_tz()) start_time = dateutils.format_iso8601_datetime(now) delta = { 'start_time': start_time, 'state': 'running', 'disregard': 'ignored', 'progress_report': { 'report-id': 'my-progress' } } updated = TaskStatusManager.update_task_status(task_id, delta) task_status = TaskStatusManager.find_by_task_id(task_id) self.assertEqual(task_status['start_time'], delta['start_time']) # Make sure that parse_iso8601_datetime is able to parse the start_time without errors dateutils.parse_iso8601_datetime(task_status['start_time']) self.assertEqual(task_status['state'], delta['state']) self.assertEqual(task_status['progress_report'], delta['progress_report']) self.assertEqual(task_status['queue'], queue) self.assertEqual(updated['start_time'], delta['start_time']) self.assertEqual(updated['state'], delta['state']) self.assertEqual(updated['progress_report'], delta['progress_report']) self.assertTrue('disregard' not in updated) self.assertTrue('disregard' not in task_status)
def __call__(self, *args, **kwargs): """ This overrides CeleryTask's __call__() method. We use this method for task state tracking of Pulp tasks. """ # Check task status and skip running the task if task state is 'canceled'. task_status = TaskStatusManager.find_by_task_id( task_id=self.request.id) if task_status and task_status[ 'state'] == constants.CALL_CANCELED_STATE: logger.debug("Task cancel received for task-id : [%s]" % self.request.id) return # Update start_time and set the task state to 'running' for asynchronous tasks. # Skip updating status for eagerly executed tasks, since we don't want to track # synchronous tasks in our database. if not self.request.called_directly: now = datetime.now(dateutils.utc_tz()) start_time = dateutils.format_iso8601_datetime(now) # Using 'upsert' to avoid a possible race condition described in the apply_async method # above. TaskStatus.get_collection().update({'task_id': self.request.id}, { '$set': { 'state': constants.CALL_RUNNING_STATE, 'start_time': start_time } }, upsert=True) # Run the actual task logger.debug("Running task : [%s]" % self.request.id) return super(Task, self).__call__(*args, **kwargs)
def cancel(task_id): """ Cancel the task that is represented by the given task_id. This method cancels only the task with given task_id, not the spawned tasks. This also updates task's state to 'canceled'. :param task_id: The ID of the task you wish to cancel :type task_id: basestring :raises MissingResource: if a task with given task_id does not exist :raises PulpCodedException: if given task is already in a complete state """ task_status = TaskStatusManager.find_by_task_id(task_id) if task_status is None: raise MissingResource(task_id) if task_status['state'] in constants.CALL_COMPLETE_STATES: # If the task is already done, just stop msg = _('Task [%(task_id)s] already in a completed state: %(state)s') logger.info(msg % {'task_id': task_id, 'state': task_status['state']}) return controller.revoke(task_id, terminate=True) TaskStatus.get_collection().find_and_modify( { 'task_id': task_id, 'state': { '$nin': constants.CALL_COMPLETE_STATES } }, {'$set': { 'state': constants.CALL_CANCELED_STATE }}) msg = _('Task canceled: %(task_id)s.') msg = msg % {'task_id': task_id} logger.info(msg)
def test_on_success_handler_spawned_task_dict(self, mock_request): """ Make sure that overridden on_success handler updates task status correctly """ retval = tasks.TaskResult(spawned_tasks=[{ 'task_id': 'foo-id' }], result='bar') task_id = str(uuid.uuid4()) args = [1, 'b', 'iii'] kwargs = { '1': 'for the money', 'tags': ['test_tags'], 'queue': WORKER_2_QUEUE } mock_request.called_directly = False task_status = TaskStatusManager.create_task_status( task_id, 'some_queue') self.assertEqual(task_status['state'], 'waiting') self.assertEqual(task_status['finish_time'], None) task = tasks.Task() task.on_success(retval, task_id, args, kwargs) new_task_status = TaskStatusManager.find_by_task_id(task_id) self.assertEqual(new_task_status['state'], 'finished') self.assertEqual(new_task_status['result'], 'bar') self.assertFalse(new_task_status['finish_time'] is None) self.assertEqual(new_task_status['spawned_tasks'], ['foo-id'])
def test_on_success_handler_async_result(self, mock_request): """ Make sure that overridden on_success handler updates task status correctly """ retval = AsyncResult('foo-id') task_id = str(uuid.uuid4()) args = [1, 'b', 'iii'] kwargs = { '1': 'for the money', 'tags': ['test_tags'], 'queue': WORKER_2_QUEUE } mock_request.called_directly = False task_status = TaskStatusManager.create_task_status( task_id, 'some_queue') self.assertEqual(task_status['state'], 'waiting') self.assertEqual(task_status['finish_time'], None) task = tasks.Task() task.on_success(retval, task_id, args, kwargs) new_task_status = TaskStatusManager.find_by_task_id(task_id) self.assertEqual(new_task_status['state'], 'finished') self.assertEqual(new_task_status['result'], None) self.assertFalse(new_task_status['finish_time'] is None) # Make sure that parse_iso8601_datetime is able to parse the finish_time without errors dateutils.parse_iso8601_datetime(new_task_status['finish_time']) self.assertEqual(new_task_status['spawned_tasks'], ['foo-id'])
def test_update_task_status(self): """ Tests the successful operation of update_task_status(). """ task_id = self.get_random_uuid() queue = 'special_queue' tags = ['test-tag1', 'test-tag2'] state = 'waiting' TaskStatusManager.create_task_status(task_id, queue, tags, state) delta = {'start_time': dateutils.now_utc_timestamp(), 'state': 'running', 'disregard': 'ignored', 'progress_report': {'report-id': 'my-progress'}} updated = TaskStatusManager.update_task_status(task_id, delta) task_status = TaskStatusManager.find_by_task_id(task_id) self.assertEqual(task_status['start_time'], delta['start_time']) self.assertEqual(task_status['state'], delta['state']) self.assertEqual(task_status['progress_report'], delta['progress_report']) self.assertEqual(task_status['queue'], queue) self.assertEqual(updated['start_time'], delta['start_time']) self.assertEqual(updated['state'], delta['state']) self.assertEqual(updated['progress_report'], delta['progress_report']) self.assertTrue('disregard' not in updated) self.assertTrue('disregard' not in task_status)
def test_on_success_handler_spawned_task_status(self, mock_request): """ Make sure that overridden on_success handler updates task status correctly """ async_result = AsyncResult('foo-id') retval = tasks.TaskResult(error=PulpException('error-foo'), result='bar') retval.spawned_tasks = [async_result] task_id = str(uuid.uuid4()) args = [1, 'b', 'iii'] kwargs = {'1': 'for the money', 'tags': ['test_tags'], 'queue': RESERVED_WORKER_2} mock_request.called_directly = False task_status = TaskStatusManager.create_task_status(task_id, 'some_queue') self.assertEqual(task_status['state'], None) self.assertEqual(task_status['finish_time'], None) task = tasks.Task() task.on_success(retval, task_id, args, kwargs) new_task_status = TaskStatusManager.find_by_task_id(task_id) self.assertEqual(new_task_status['state'], 'finished') self.assertEqual(new_task_status['result'], 'bar') self.assertEqual(new_task_status['error']['description'], 'error-foo') self.assertFalse(new_task_status['finish_time'] == None) self.assertEqual(new_task_status['spawned_tasks'], ['foo-id'])
def __call__(self, *args, **kwargs): """ This overrides CeleryTask's __call__() method. We use this method for task state tracking of Pulp tasks. """ # Add task_id to the task context, so that agent and plugins have access to the task id. # There are a few other attributes in the context as defined by old dispatch system. # These are unused right now. These should be removed when we cleanup the dispatch folder # after the migration to celery is complete. task_context = dispatch_factory.context() task_context.call_request_id = self.request.id # Check task status and skip running the task if task state is 'canceled'. task_status = TaskStatusManager.find_by_task_id(task_id=self.request.id) if task_status and task_status['state'] == dispatch_constants.CALL_CANCELED_STATE: logger.debug("Task cancel received for task-id : [%s]" % self.request.id) return # Update start_time and set the task state to 'running' for asynchronous tasks. # Skip updating status for eagerly executed tasks, since we don't want to track # synchronous tasks in our database. if not self.request.called_directly: # Using 'upsert' to avoid a possible race condition described in the apply_async method # above. TaskStatus.get_collection().update( {'task_id': self.request.id}, {'$set': {'state': dispatch_constants.CALL_RUNNING_STATE, 'start_time': dateutils.now_utc_timestamp()}}, upsert=True) # Run the actual task logger.debug("Running task : [%s]" % self.request.id) return super(Task, self).__call__(*args, **kwargs)
def __call__(self, *args, **kwargs): """ This overrides CeleryTask's __call__() method. We use this method for task state tracking of Pulp tasks. """ # Check task status and skip running the task if task state is 'canceled'. task_status = TaskStatusManager.find_by_task_id(task_id=self.request.id) if task_status and task_status['state'] == dispatch_constants.CALL_CANCELED_STATE: logger.debug("Task cancel received for task-id : [%s]" % self.request.id) return # Update start_time and set the task state to 'running' for asynchronous tasks. # Skip updating status for eagerly executed tasks, since we don't want to track # synchronous tasks in our database. if not self.request.called_directly: now = datetime.now(dateutils.utc_tz()) start_time = dateutils.format_iso8601_datetime(now) # Using 'upsert' to avoid a possible race condition described in the apply_async method # above. TaskStatus.get_collection().update( {'task_id': self.request.id}, {'$set': {'state': dispatch_constants.CALL_RUNNING_STATE, 'start_time': start_time}}, upsert=True) # Run the actual task logger.debug("Running task : [%s]" % self.request.id) return super(Task, self).__call__(*args, **kwargs)
def test_on_success_with_canceled_task(self, mock_request): """ Make sure on_success() does not move a canceled Task to 'finished' state. """ retval = 'random_return_value' task_id = str(uuid.uuid4()) args = [1, 'b', 'iii'] kwargs = { '1': 'for the money', 'tags': ['test_tags'], 'queue': WORKER_2_QUEUE } mock_request.called_directly = False task_status = TaskStatusManager.create_task_status( task_id, 'some_queue', state=CALL_CANCELED_STATE) task = tasks.Task() # This should not update the task status to finished, since this task was canceled. task.on_success(retval, task_id, args, kwargs) updated_task_status = TaskStatusManager.find_by_task_id(task_id) # Make sure the task is still canceled. self.assertEqual(updated_task_status['state'], CALL_CANCELED_STATE) self.assertEqual(updated_task_status['result'], retval) self.assertFalse(updated_task_status['finish_time'] is None) # Make sure that parse_iso8601_datetime is able to parse the finish_time without errors dateutils.parse_iso8601_datetime(updated_task_status['finish_time'])
def test_spawned_task_status(self, mock_request): async_result = AsyncResult('foo-id') retval = tasks.TaskResult(error=PulpException('error-foo'), result='bar') retval.spawned_tasks = [async_result] task_id = str(uuid.uuid4()) args = [1, 'b', 'iii'] kwargs = { '1': 'for the money', 'tags': ['test_tags'], 'routing_key': WORKER_2 } mock_request.called_directly = False task_status = TaskStatusManager.create_task_status(task_id) self.assertEqual(task_status['state'], 'waiting') self.assertEqual(task_status['finish_time'], None) task = tasks.Task() task.on_success(retval, task_id, args, kwargs) new_task_status = TaskStatusManager.find_by_task_id(task_id) self.assertEqual(new_task_status['state'], 'finished') self.assertEqual(new_task_status['result'], 'bar') self.assertEqual(new_task_status['error']['description'], 'error-foo') self.assertFalse(new_task_status['finish_time'] is None) # Make sure that parse_iso8601_datetime is able to parse the finish_time without errors dateutils.parse_iso8601_datetime(new_task_status['finish_time']) self.assertEqual(new_task_status['spawned_tasks'], ['foo-id'])
def test_spawned_task_dict(self, mock_request): retval = tasks.TaskResult(spawned_tasks=[{ 'task_id': 'foo-id' }], result='bar') task_id = str(uuid.uuid4()) args = [1, 'b', 'iii'] kwargs = { '1': 'for the money', 'tags': ['test_tags'], 'routing_key': WORKER_2 } mock_request.called_directly = False task_status = TaskStatusManager.create_task_status(task_id) self.assertEqual(task_status['state'], 'waiting') self.assertEqual(task_status['finish_time'], None) task = tasks.Task() task.on_success(retval, task_id, args, kwargs) new_task_status = TaskStatusManager.find_by_task_id(task_id) self.assertEqual(new_task_status['state'], 'finished') self.assertEqual(new_task_status['result'], 'bar') self.assertFalse(new_task_status['finish_time'] is None) self.assertEqual(new_task_status['spawned_tasks'], ['foo-id'])
def test_cancel_after_task_finished(self, logger, revoke): task_id = '1234abcd' test_queue = AvailableQueue('test_queue') TaskStatusManager.create_task_status(task_id, test_queue.name, state=CALL_FINISHED_STATE) self.assertRaises(PulpCodedException, tasks.cancel, task_id) task_status = TaskStatusManager.find_by_task_id(task_id) self.assertEqual(task_status['state'], CALL_FINISHED_STATE)
def __init__(self, event_type, payload): self.event_type = event_type self.payload = payload try: task_id = celery.current_task.request.id self.call_report = TaskStatusManager.find_by_task_id(task_id) except AttributeError: self.call_report = None
def test_DELETE_completed_celery_task(self): """ Test the DELETE() method does not change the state of a task that is already complete """ task_id = '1234abcd' TaskStatusManager.create_task_status(task_id, state=constants.CALL_FINISHED_STATE) self.task_resource.DELETE(task_id) task_status = TaskStatusManager.find_by_task_id(task_id) self.assertEqual(task_status['state'], constants.CALL_FINISHED_STATE)
def GET(self, task_id): task = TaskStatusManager.find_by_task_id(task_id) if task is None: raise MissingResource(task_id) else: link = serialization.link.link_obj('/pulp/api/v2/tasks/%s/' % task_id) task.update(link) task.update(serialization.dispatch.spawned_tasks(task)) return self.ok(task)
def test_cancel_after_task_finished(self, logger, revoke): task_id = '1234abcd' now = datetime.utcnow() test_worker = Worker('test_worker', now) TaskStatusManager.create_task_status(task_id, test_worker.name, state=CALL_FINISHED_STATE) self.assertRaises(PulpCodedException, tasks.cancel, task_id) task_status = TaskStatusManager.find_by_task_id(task_id) self.assertEqual(task_status['state'], CALL_FINISHED_STATE)
def test_DELETE_completed_celery_task(self): """ Test the DELETE() method does not change the state of a task that is already complete """ task_id = '1234abcd' TaskStatusManager.create_task_status( task_id, state=constants.CALL_FINISHED_STATE) self.task_resource.DELETE(task_id) task_status = TaskStatusManager.find_by_task_id(task_id) self.assertEqual(task_status['state'], constants.CALL_FINISHED_STATE)
def test_cancel_after_task_canceled(self, *unused_mocks): """ Test that canceling a task that was already canceled results in no change to the task state. """ task_id = '1234abcd' TaskStatusManager.create_task_status(task_id, 'test_worker', state=CALL_CANCELED_STATE) tasks.cancel(task_id) task_status = TaskStatusManager.find_by_task_id(task_id) self.assertEqual(task_status['state'], CALL_CANCELED_STATE)
def test_cancel_after_task_finished(self, logger, revoke): """ Test that canceling a task that is already finished results in no change to the task state. """ task_id = '1234abcd' TaskStatusManager.create_task_status(task_id, 'test_worker', state=CALL_FINISHED_STATE) tasks.cancel(task_id) task_status = TaskStatusManager.find_by_task_id(task_id) self.assertEqual(task_status['state'], CALL_FINISHED_STATE)
def test_cancel_successful(self, logger, revoke): task_id = '1234abcd' TaskStatusManager.create_task_status(task_id) tasks.cancel(task_id) revoke.assert_called_once_with(task_id, terminate=True) self.assertEqual(logger.info.call_count, 1) log_msg = logger.info.mock_calls[0][1][0] self.assertTrue(task_id in log_msg) self.assertTrue('Task canceled' in log_msg) task_status = TaskStatusManager.find_by_task_id(task_id) self.assertEqual(task_status['state'], CALL_CANCELED_STATE)
def GET(self, task_id): task = TaskStatusManager.find_by_task_id(task_id) if task is None: raise MissingResource(task_id) else: link = serialization.link.link_obj('/pulp/api/v2/tasks/%s/' % task_id) task.update(link) task.update(serialization.dispatch.spawned_tasks(task)) if 'worker_name' in task: queue_name = Worker(task['worker_name'], datetime.now()).queue_name task.update({'queue': queue_name}) return self.ok(task)
def test_task_status_not_modified_when_task_status_exists(self, apply_async): args = [1, 'b', 'iii'] kwargs = {'a': 'for the money', 'tags': ['test_tags']} task_id = 'test_task_id' TaskStatusManager.create_task_status(task_id, 'test-worker', state=CALL_CANCELED_STATE) apply_async.return_value = celery.result.AsyncResult(task_id) task = tasks.Task() task.apply_async(*args, **kwargs) task_status = TaskStatusManager.find_by_task_id(task_id) self.assertEqual(task_status['state'], 'canceled') self.assertEqual(task_status['start_time'], None)
def test_task_status_not_modified_when_task_status_exists( self, apply_async): args = [1, 'b', 'iii'] kwargs = {'a': 'for the money', 'tags': ['test_tags']} task_id = 'test_task_id' TaskStatusManager.create_task_status(task_id, 'test-worker', state=CALL_CANCELED_STATE) apply_async.return_value = celery.result.AsyncResult(task_id) task = tasks.Task() task.apply_async(*args, **kwargs) task_status = TaskStatusManager.find_by_task_id(task_id) self.assertEqual(task_status['state'], 'canceled') self.assertEqual(task_status['start_time'], None)
def test_apply_async_task_canceled(self, apply_async): """ Assert that apply_async() honors 'canceled' task status. """ args = [1, 'b', 'iii'] kwargs = {'1': 'for the money', 'tags': ['test_tags']} task_id = 'test_task_id' TaskStatusManager.create_task_status(task_id, AvailableQueue('test-queue'), state=CALL_CANCELED_STATE) apply_async.return_value = celery.result.AsyncResult(task_id) task = tasks.Task() task.apply_async(*args, **kwargs) task_status = TaskStatusManager.find_by_task_id(task_id) self.assertEqual(task_status['state'], 'canceled') self.assertEqual(task_status['start_time'], None)
def from_task_status(cls, task_id): """ Factory method that forms a CallReport using existing TaskStatus for given task id. :param cls: CallReport class :type cls: type :param task_id: task id to be used to lookup task status :type task_id: basestring :return: CallReport instance :rtype: CallReport """ task_status = TaskStatusManager.find_by_task_id(task_id) if task_status: return CallReport.from_task_status_dict(task_status) else: call_report = cls(task_id) return call_report
def test_with_canceled_task(self, mock_request): retval = 'random_return_value' task_id = str(uuid.uuid4()) args = [1, 'b', 'iii'] kwargs = {'1': 'for the money', 'tags': ['test_tags'], 'routing_key': WORKER_2} mock_request.called_directly = False TaskStatusManager.create_task_status(task_id, state=CALL_CANCELED_STATE) task = tasks.Task() # This should not update the task status to finished, since this task was canceled. task.on_success(retval, task_id, args, kwargs) updated_task_status = TaskStatusManager.find_by_task_id(task_id) # Make sure the task is still canceled. self.assertEqual(updated_task_status['state'], CALL_CANCELED_STATE) self.assertEqual(updated_task_status['result'], retval) self.assertFalse(updated_task_status['finish_time'] is None) # Make sure that parse_iso8601_datetime is able to parse the finish_time without errors dateutils.parse_iso8601_datetime(updated_task_status['finish_time'])
def test_apply_async_task_canceled(self, apply_async): """ Assert that apply_async() honors 'canceled' task status. """ args = [1, 'b', 'iii'] kwargs = {'1': 'for the money', 'tags': ['test_tags']} task_id = 'test_task_id' now = datetime.utcnow() TaskStatusManager.create_task_status(task_id, Worker('test-worker', now), state=CALL_CANCELED_STATE) apply_async.return_value = celery.result.AsyncResult(task_id) task = tasks.Task() task.apply_async(*args, **kwargs) task_status = TaskStatusManager.find_by_task_id(task_id) self.assertEqual(task_status['state'], 'canceled') self.assertEqual(task_status['start_time'], None)
def on_success(self, retval, task_id, args, kwargs): """ This overrides the success handler run by the worker when the task executes successfully. It updates state, finish_time and traceback of the relevant task status for asynchronous tasks. Skip updating status for synchronous tasks. :param retval: The return value of the task. :param task_id: Unique id of the executed task. :param args: Original arguments for the executed task. :param kwargs: Original keyword arguments for the executed task. """ logger.debug("Task successful : [%s]" % task_id) if not self.request.called_directly: now = datetime.now(dateutils.utc_tz()) finish_time = dateutils.format_iso8601_datetime(now) delta = {'finish_time': finish_time, 'result': retval} task_status = TaskStatusManager.find_by_task_id(task_id) # Only set the state to finished if it's not already in a complete state. This is # important for when the task has been canceled, so we don't move the task from canceled # to finished. if task_status['state'] not in constants.CALL_COMPLETE_STATES: delta['state'] = constants.CALL_FINISHED_STATE if isinstance(retval, TaskResult): delta['result'] = retval.return_value if retval.error: delta['error'] = retval.error.to_dict() if retval.spawned_tasks: task_list = [] for spawned_task in retval.spawned_tasks: if isinstance(spawned_task, AsyncResult): task_list.append(spawned_task.task_id) elif isinstance(spawned_task, dict): task_list.append(spawned_task['task_id']) delta['spawned_tasks'] = task_list if isinstance(retval, AsyncResult): delta['spawned_tasks'] = [ retval.task_id, ] delta['result'] = None TaskStatusManager.update_task_status(task_id=task_id, delta=delta)
def test_updates_task_status_correctly(self, mock_request): retval = 'random_return_value' task_id = str(uuid.uuid4()) args = [1, 'b', 'iii'] kwargs = {'1': 'for the money', 'tags': ['test_tags'], 'routing_key': WORKER_2} mock_request.called_directly = False task_status = TaskStatusManager.create_task_status(task_id) self.assertEqual(task_status['state'], 'waiting') self.assertEqual(task_status['finish_time'], None) task = tasks.Task() task.on_success(retval, task_id, args, kwargs) new_task_status = TaskStatusManager.find_by_task_id(task_id) self.assertEqual(new_task_status['state'], 'finished') self.assertEqual(new_task_status['result'], retval) self.assertFalse(new_task_status['finish_time'] is None) # Make sure that parse_iso8601_datetime is able to parse the finish_time without errors dateutils.parse_iso8601_datetime(new_task_status['finish_time'])
def test_spawned_task_dict(self, mock_request): retval = tasks.TaskResult(spawned_tasks=[{'task_id': 'foo-id'}], result='bar') task_id = str(uuid.uuid4()) args = [1, 'b', 'iii'] kwargs = {'1': 'for the money', 'tags': ['test_tags'], 'routing_key': WORKER_2} mock_request.called_directly = False task_status = TaskStatusManager.create_task_status(task_id) self.assertEqual(task_status['state'], 'waiting') self.assertEqual(task_status['finish_time'], None) task = tasks.Task() task.on_success(retval, task_id, args, kwargs) new_task_status = TaskStatusManager.find_by_task_id(task_id) self.assertEqual(new_task_status['state'], 'finished') self.assertEqual(new_task_status['result'], 'bar') self.assertFalse(new_task_status['finish_time'] is None) self.assertEqual(new_task_status['spawned_tasks'], ['foo-id'])
def on_success(self, retval, task_id, args, kwargs): """ This overrides the success handler run by the worker when the task executes successfully. It updates state, finish_time and traceback of the relevant task status for asynchronous tasks. Skip updating status for synchronous tasks. :param retval: The return value of the task. :param task_id: Unique id of the executed task. :param args: Original arguments for the executed task. :param kwargs: Original keyword arguments for the executed task. """ logger.debug("Task successful : [%s]" % task_id) if not self.request.called_directly: now = datetime.now(dateutils.utc_tz()) finish_time = dateutils.format_iso8601_datetime(now) delta = {'finish_time': finish_time, 'result': retval} task_status = TaskStatusManager.find_by_task_id(task_id) # Only set the state to finished if it's not already in a complete state. This is # important for when the task has been canceled, so we don't move the task from canceled # to finished. if task_status['state'] not in constants.CALL_COMPLETE_STATES: delta['state'] = constants.CALL_FINISHED_STATE if isinstance(retval, TaskResult): delta['result'] = retval.return_value if retval.error: delta['error'] = retval.error.to_dict() if retval.spawned_tasks: task_list = [] for spawned_task in retval.spawned_tasks: if isinstance(spawned_task, AsyncResult): task_list.append(spawned_task.task_id) elif isinstance(spawned_task, dict): task_list.append(spawned_task['task_id']) delta['spawned_tasks'] = task_list if isinstance(retval, AsyncResult): delta['spawned_tasks'] = [retval.task_id, ] delta['result'] = None TaskStatusManager.update_task_status(task_id=task_id, delta=delta)
def test_on_success_handler(self, mock_request): """ Make sure that overridden on_success handler updates task status correctly """ retval = 'random_return_value' task_id = str(uuid.uuid4()) args = [1, 'b', 'iii'] kwargs = {'1': 'for the money', 'tags': ['test_tags'], 'queue': RESERVED_WORKER_2} mock_request.called_directly = False task_status = TaskStatusManager.create_task_status(task_id, 'some_queue') self.assertEqual(task_status['state'], None) self.assertEqual(task_status['finish_time'], None) task = tasks.Task() task.on_success(retval, task_id, args, kwargs) new_task_status = TaskStatusManager.find_by_task_id(task_id) self.assertEqual(new_task_status['state'], 'finished') self.assertEqual(new_task_status['result'], retval) self.assertFalse(new_task_status['finish_time'] == None)
def test_on_success_handler_spawned_task_dict(self, mock_request): """ Make sure that overridden on_success handler updates task status correctly """ retval = tasks.TaskResult(spawned_tasks=[{'task_id': 'foo-id'}], result='bar') task_id = str(uuid.uuid4()) args = [1, 'b', 'iii'] kwargs = {'1': 'for the money', 'tags': ['test_tags'], 'queue': WORKER_2_QUEUE} mock_request.called_directly = False task_status = TaskStatusManager.create_task_status(task_id, 'some_queue') self.assertEqual(task_status['state'], 'waiting') self.assertEqual(task_status['finish_time'], None) task = tasks.Task() task.on_success(retval, task_id, args, kwargs) new_task_status = TaskStatusManager.find_by_task_id(task_id) self.assertEqual(new_task_status['state'], 'finished') self.assertEqual(new_task_status['result'], 'bar') self.assertFalse(new_task_status['finish_time'] is None) self.assertEqual(new_task_status['spawned_tasks'], ['foo-id'])
def test_updates_task_status_correctly(self, mock_request): retval = 'random_return_value' task_id = str(uuid.uuid4()) args = [1, 'b', 'iii'] kwargs = { '1': 'for the money', 'tags': ['test_tags'], 'routing_key': WORKER_2 } mock_request.called_directly = False task_status = TaskStatusManager.create_task_status(task_id) self.assertEqual(task_status['state'], 'waiting') self.assertEqual(task_status['finish_time'], None) task = tasks.Task() task.on_success(retval, task_id, args, kwargs) new_task_status = TaskStatusManager.find_by_task_id(task_id) self.assertEqual(new_task_status['state'], 'finished') self.assertEqual(new_task_status['result'], retval) self.assertFalse(new_task_status['finish_time'] is None) # Make sure that parse_iso8601_datetime is able to parse the finish_time without errors dateutils.parse_iso8601_datetime(new_task_status['finish_time'])