def callback(body, message): """ :param dict body: ``body`` is the message sent by the task. The dict should contain 2 keys: `job_id` and `num_items` (to indicate the number of sources computed). Both values are `int`. :param message: A :class:`kombu.transport.pyamqplib.Message`, which contains metadata about the message (including content type, channel, etc.). See kombu docs for more details. """ job_id = body['job_id'] num_items = body['num_items'] assert job_id == self.job.id self.progress['computed'] += num_items self.task_completed_hook(body) logs.log_percent_complete(job_id, "hazard") # Once we receive a completion signal, enqueue the next # piece of work (if there's anything left to be done). try: queue_next(self.core_calc_task, task_arg_gen.next()) except StopIteration: # There are no more tasks to dispatch; now we just need # to wait until all tasks signal completion. self.progress['in_queue'] -= 1 message.ack() logs.LOG.info('A task was completed. Tasks now in queue: %s' % self.progress['in_queue'])
def test_log_percent_complete_with_invalid_area(self): # nothing is reported, -1 is returned job_id = 11 with mock.patch("openquake.engine.logs.LOG.progress") as lpm: rv = logs.log_percent_complete(job_id, "invalid calculation") self.assertEqual(-1, rv) self.assertEqual(0, lpm.call_count)
def test_log_percent_complete_with_zero_percent_done(self): # nothing is reported since the percentage complete value is zero job_id = 13 stats.pk_set(job_id, "nhzrd_total", 100) stats.pk_set(job_id, "nhzrd_done", 0) stats.pk_set(job_id, "lvr", -1) with mock.patch("openquake.engine.logs.LOG.progress") as lpm: rv = logs.log_percent_complete(job_id, "hazard") self.assertEqual(0, rv) self.assertEqual(0, lpm.call_count)
def test_log_percent_complete_with_almost_same_percentage_value(self): # only 1 value is reported when the percentage complete value is # almost the same (12.6 versus 12). job_id = 12 stats.pk_set(job_id, "nhzrd_total", 366) stats.pk_set(job_id, "nhzrd_done", 46) stats.pk_set(job_id, "lvr", 12) with mock.patch("openquake.engine.logs.LOG.progress") as lpm: rv = logs.log_percent_complete(job_id, "hazard") self.assertEqual(12, rv) self.assertEqual(0, lpm.call_count)
def test_log_percent_complete_with_new_percentage_value(self): # the percentage complete is reported since it exceeds the last value # reported job_id = 14 stats.pk_set(job_id, "nhzrd_total", 100) stats.pk_set(job_id, "nhzrd_done", 20) stats.pk_set(job_id, "lvr", 12) with mock.patch("openquake.engine.logs.LOG.progress") as lpm: rv = logs.log_percent_complete(job_id, "hazard") self.assertEqual(20, rv) self.assertEqual(1, lpm.call_count) self.assertEqual("hazard 20% complete", lpm.call_args_list[0][0][0])
def callback(body, message): """ :param dict body: ``body`` is the message sent by the task. The dict should contain 2 keys: `job_id` and `num_sources` (to indicate the number of sources computed). Both values are `int`. :param message: A :class:`kombu.transport.pyamqplib.Message`, which contains metadata about the message (including content type, channel, etc.). See kombu docs for more details. """ job_id = body['job_id'] num_items = body['num_items'] calc_type = body['calc_type'] assert job_id == self.job.id # Log a progress message logs.log_percent_complete(job_id, 'hazard') if self.disagg_phase: assert calc_type == 'disagg' # We're in the second phase of the calculation; just keep # queuing tasks (if there are any left) and wait for everything # to finish. try: base.queue_next( self.core_calc_task, disagg_task_arg_gen.next()) except StopIteration: # There are no more tasks to dispatch; now we just need to # wait until all of the tasks signal completion. self.progress['in_queue'] -= 1 else: logs.LOG.debug('* queuing the next disagg task') else: if calc_type == 'hazard_curve': # record progress specifically for hazard curve computation self.progress['hc_computed'] += num_items if (self.progress['hc_computed'] == self.progress['hc_total']): # we just finished the last hazard curve task ... self.progress['in_queue'] -= 1 # ... and we're switching to disagg phase self.disagg_phase = True logs.LOG.progress('Hazard curve computation complete', indent=True) logs.LOG.progress('Starting disaggregation', indent=True) # Finalize the hazard curves, so the disaggregation # can find curves by their point geometry: self.finalize_hazard_curves() logs.LOG.debug('* queuing initial disagg tasks') # the task queue should be empty, so let's fill it up # with disagg tasks: for _ in xrange(concurrent_tasks): try: base.queue_next( self.core_calc_task, disagg_task_arg_gen.next()) except StopIteration: # If we get a `StopIteration` here, that means # we have number of disagg tasks < # concurrent_tasks. break else: self.progress['in_queue'] += 1 logs.LOG.info('Tasks now in queue: %s' % self.progress['in_queue']) else: # we're not done computing hazard curves; enqueue the # next task try: base.queue_next( self.core_calc_task, hc_task_arg_gen.next()) except StopIteration: # No more hazard curve tasks left to enqueue; # now we just wait for this phase to complete. self.progress['in_queue'] -= 1 else: logs.LOG.debug( '* queueing the next hazard curve task') else: # we're in the hazard curve phase, but the completed # message did not have a 'hazard_curve' type raise RuntimeError( 'Unexpected message `calc_type`: "%s"' % calc_type) # Last thing, update the 'computed' counter and acknowledge the # message: self.progress['computed'] += num_items message.ack() logs.LOG.info('A task was completed. Tasks now in queue: %s' % self.progress['in_queue'])
def callback(body, message): """ :param dict body: ``body`` is the message sent by the task. The dict should contain 2 keys: `job_id` and `num_sources` (to indicate the number of sources computed). Both values are `int`. :param message: A :class:`kombu.transport.pyamqplib.Message`, which contains metadata about the message (including content type, channel, etc.). See kombu docs for more details. """ job_id = body['job_id'] num_items = body['num_items'] calc_type = body['calc_type'] assert job_id == self.job.id # Log a progress message logs.log_percent_complete(job_id, 'hazard') if self.disagg_phase: assert calc_type == 'disagg' # We're in the second phase of the calculation; just keep # queuing tasks (if there are any left) and wait for everything # to finish. try: base.queue_next(self.core_calc_task, disagg_task_arg_gen.next()) except StopIteration: # There are no more tasks to dispatch; now we just need to # wait until all of the tasks signal completion. self.progress['in_queue'] -= 1 else: logs.LOG.debug('* queuing the next disagg task') else: if calc_type == 'hazard_curve': # record progress specifically for hazard curve computation self.progress['hc_computed'] += num_items if (self.progress['hc_computed'] == self.progress['hc_total']): # we just finished the last hazard curve task ... self.progress['in_queue'] -= 1 # ... and we're switching to disagg phase self.disagg_phase = True logs.LOG.progress('Hazard curve computation complete', indent=True) logs.LOG.progress('Starting disaggregation', indent=True) # Finalize the hazard curves, so the disaggregation # can find curves by their point geometry: self.finalize_hazard_curves() logs.LOG.debug('* queuing initial disagg tasks') # the task queue should be empty, so let's fill it up # with disagg tasks: for _ in xrange(concurrent_tasks): try: base.queue_next(self.core_calc_task, disagg_task_arg_gen.next()) except StopIteration: # If we get a `StopIteration` here, that means # we have number of disagg tasks < # concurrent_tasks. break else: self.progress['in_queue'] += 1 logs.LOG.info('Tasks now in queue: %s' % self.progress['in_queue']) else: # we're not done computing hazard curves; enqueue the # next task try: base.queue_next(self.core_calc_task, hc_task_arg_gen.next()) except StopIteration: # No more hazard curve tasks left to enqueue; # now we just wait for this phase to complete. self.progress['in_queue'] -= 1 else: logs.LOG.debug( '* queueing the next hazard curve task') else: # we're in the hazard curve phase, but the completed # message did not have a 'hazard_curve' type raise RuntimeError('Unexpected message `calc_type`: "%s"' % calc_type) # Last thing, update the 'computed' counter and acknowledge the # message: self.progress['computed'] += num_items message.ack() logs.LOG.info('A task was completed. Tasks now in queue: %s' % self.progress['in_queue'])