def _run_replication_task(self, replication_task: ReplicationTask): try: shell = replication_task.transport.shell( replication_task.transport) try: ReplicationTaskLoggingLevelFilter.levels[ replication_task.id] = replication_task.logging_level run_replication_tasks(self.local_shell, replication_task.transport, shell, [replication_task], self.observer) finally: shell.close() except Exception: logger.error( "Unhandled exception while running replication task %r", replication_task, exc_info=True) finally: with self.tasks_lock: self.running_tasks.remove(replication_task) self._spawn_pending_tasks() if not self.running_tasks and not self.retention_running: self._spawn_retention()
def test__run_replication_tasks__do_not_try_second_part_if_first_has_failed(): task1 = Mock(direction=ReplicationDirection.PUSH, source_datasets=["data/work"], recursive=True, retries=1) task2 = Mock(direction=ReplicationDirection.PUSH, source_datasets=["data", "data/work/ix"], recursive=False, retries=1) def run_replication_task_part__side_effect(replication_task, source_dataset, src_context, dst_context, observer): if replication_task == task2: if source_dataset == "data": raise ReplicationError("This should fail") else: raise Exception("This should never be reached") with patch("zettarepl.replication.run.run_replication_task_part", Mock(side_effect=run_replication_task_part__side_effect) ) as run_replication_task_part: run_replication_tasks(Mock(), Mock(), Mock(), [task1, task2]) assert run_replication_task_part.call_args_list == [ call(task2, "data", ANY, ANY, None), call(task1, "data/work", ANY, ANY, None), ]
def test__run_replication_tasks(tasks, parts): for task in tasks: task.retries = 1 with patch("zettarepl.replication.run.run_replication_task_part") as run_replication_task_part: run_replication_tasks(Mock(), Mock(), Mock(), tasks) assert run_replication_task_part.mock_calls == [ call(tasks[task_id], source_dataset, ANY, ANY, None) for task_id, source_dataset in parts ]
def test__run_replication_tasks__only_notify_success_after_last_part(): task1 = Mock(direction=ReplicationDirection.PUSH, retries=1) task2 = Mock(direction=ReplicationDirection.PUSH, retries=1) with patch("zettarepl.replication.run.calculate_replication_tasks_parts", Mock(return_value=[(task1, Mock()), (task2, Mock()), (task1, Mock())])): with patch("zettarepl.replication.run.run_replication_task_part"): observer = Mock() run_replication_tasks(Mock(), Mock(), Mock(), [task1, task2], observer) assert [c[0][0].task_id for c in observer.call_args_list if isinstance(c[0][0], ReplicationTaskSuccess)] ==\ [task2.id, task1.id]
def _run_replication_tasks(self, replication_tasks): for transport, replication_tasks in self._transport_for_replication_tasks( replication_tasks): remote_shell = self._get_shell(transport) push_replication_tasks, replication_tasks = bisect( self._is_push_replication_task, replication_tasks) run_replication_tasks(self.local_shell, transport, remote_shell, push_replication_tasks) pull_replication_tasks, replication_tasks = bisect( self._is_pull_replication_task, replication_tasks) run_replication_tasks(self.local_shell, transport, remote_shell, pull_replication_tasks) assert replication_tasks == []