diff --git a/README.rst b/README.rst index 15da61a..c6f0e20 100644 --- a/README.rst +++ b/README.rst @@ -245,6 +245,12 @@ Run a single test example for debugging with verbose and immediate stdout output Changelog --------- +Changes in Version 0.11.1 (2025-08-27) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +- Fix a bug where automatic port assignment would give the same port to two + different mongodb servers leading to errors such as ``Found two member configurations with same host field``. + Changes in Version 0.11.0 (2024-12-30) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/mongo_orchestration/_version.py b/mongo_orchestration/_version.py index 0deb0e3..cb73775 100644 --- a/mongo_orchestration/_version.py +++ b/mongo_orchestration/_version.py @@ -1 +1 @@ -__version__ = "0.12.0.dev0" \ No newline at end of file +__version__ = "0.11.1" \ No newline at end of file diff --git a/mongo_orchestration/process.py b/mongo_orchestration/process.py index d58dad8..dd7b542 100644 --- a/mongo_orchestration/process.py +++ b/mongo_orchestration/process.py @@ -53,9 +53,10 @@ def __init__(self, min_port=1025, max_port=2000, port_sequence=None): max_port - max port number (ignoring if 'port_sequence' is not None) port_sequence - iterate sequence which contains numbers of ports """ - if not self.__id: # singleton checker - self.__id = id(self) - self.__init_range(min_port, max_port, port_sequence) + with self._lock: + if not self.__id: # singleton checker + self.__id = id(self) + self.__init_range(min_port, max_port, port_sequence) def __init_range(self, min_port=1025, max_port=2000, port_sequence=None): if port_sequence: @@ -87,21 +88,21 @@ def release_port(self, port): def port(self, check=False): """return next opened port Args: - check - check is port realy free + check - check is port really free """ - if not self.__ports: # refresh ports if sequence is empty - self.refresh() + with self._lock: + if not self.__ports: # refresh ports if sequence is empty + self.refresh() - try: - port = self.__ports.pop() - if check: - while not self.__check_port(port): - self.release_port(port) + try: + while True: port = self.__ports.pop() - except (IndexError, KeyError): - raise IndexError("Could not find a free port,\nclosed ports: {closed}".format(closed=self.__closed)) - self.__closed.add(port) - return port + self.__closed.add(port) + if check and not self.__check_port(port): + continue + return port + except (IndexError, KeyError): + raise IndexError("Could not find a free port,\nclosed ports: {closed}".format(closed=self.__closed)) def refresh(self, only_closed=False): """refresh ports status diff --git a/mongo_orchestration/singleton.py b/mongo_orchestration/singleton.py index bec04be..034f1c5 100644 --- a/mongo_orchestration/singleton.py +++ b/mongo_orchestration/singleton.py @@ -1,6 +1,6 @@ #!/usr/bin/python # coding=utf-8 -# Copyright 2012-2014 MongoDB, Inc. +# Copyright 2012-2025 MongoDB, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -13,12 +13,14 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - +import threading class Singleton(object): _instances = {} + _lock = threading.Lock() def __new__(class_, *args, **kwargs): - if class_ not in class_._instances: - class_._instances[class_] = super(Singleton, class_).__new__(class_, *args, **kwargs) - return class_._instances[class_] + with class_._lock: + if class_ not in class_._instances: + class_._instances[class_] = super(Singleton, class_).__new__(class_, *args, **kwargs) + return class_._instances[class_]