def _handle_quorum(self, quorum: int, quorum_timeout: int, options: dict) -> Iterator[bool]: """ Context manager that handles migration application quorum by only allowing a single caller to proceed with application and preventing exit attempts until the application is completes. This ensures only a single invocation is allowed to proceed once quorum is reached and that context can only be exited once the invocation application succeeds. """ if quorum < 2: yield True return verbosity = options["verbosity"] plan = self._get_plan(**options) if not plan: yield True return database = options["database"] plan_hash = hash_plan(plan) pre_namespace = f"pre:{database}:{plan_hash}" post_namespace = f"post:{database}:{plan_hash}" if join_quorum(pre_namespace, quorum): if verbosity: self.stdout.write( "Reached pre-migrate quorum, proceeding with planned migrations..." ) yield True if verbosity: self.stdout.write("Waiting for post-migrate quorum...") duration = self._join_or_poll_until_quorum(post_namespace, quorum, quorum_timeout) if verbosity: self.stdout.write( f"Reached post-migrate quorum after {duration:.2f}s...") return yield False if verbosity: self.stdout.write("Waiting for pre-migrate quorum...") duration = self._poll_until_quorum(pre_namespace, quorum, quorum_timeout) if verbosity: self.stdout.write( f"Reached pre-migrate quorum after {duration:.2f}s...") self.stdout.write( "Waiting for migrations to be applied by remote party...") duration = self._join_or_poll_until_quorum(post_namespace, quorum, quorum_timeout) if verbosity: self.stdout.write( f"Reached post-migrate quorum after {duration:.2f}s...") self.stdout.write("Migrations applied by remote party") return
def test_app_label(self): test_app = (Migration("0001_initial", "tests"), True) other_app = (Migration("0001_initial", "other"), True) self.assertNotEqual(hash_plan([test_app]), hash_plan([other_app]))
def test_backward(self): forward = (Migration("0001_initial", "tests"), True) backward = (Migration("0001_initial", "tests"), False) self.assertNotEqual(hash_plan([forward]), hash_plan([backward]))
def test_migration_name(self): first = (Migration("0001_initial", "tests"), True) second = (Migration("0002_second", "tests"), True) self.assertNotEqual(hash_plan([first]), hash_plan([second]))
def test_stable(self): plan = [(Migration("0001_initial", "tests"), True)] self.assertEqual(hash_plan(plan), "a4a35230c7d1942265f1bc8f9ce53e05a50848be")