Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 15e4571

Browse files
author
vshepard
committedNov 1, 2024·
Don't reserve a new port if port was set up
1 parent b438515 commit 15e4571

File tree

1 file changed

+56
-32
lines changed

1 file changed

+56
-32
lines changed
 

‎testgres/node.py

Lines changed: 56 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,6 @@
9696

9797
from .operations.os_ops import ConnectionParams
9898
from .operations.local_ops import LocalOperations
99-
from .operations.remote_ops import RemoteOperations
10099

101100
InternalError = pglib.InternalError
102101
ProgrammingError = pglib.ProgrammingError
@@ -487,7 +486,7 @@ def init(self, initdb_params=None, cached=True, **kwargs):
487486
os_ops=self.os_ops,
488487
params=initdb_params,
489488
bin_path=self.bin_dir,
490-
cached=False)
489+
cached=cached)
491490

492491
# initialize default config files
493492
self.default_conf(**kwargs)
@@ -717,9 +716,9 @@ def slow_start(self, replica=False, dbname='template1', username=None, max_attem
717716
OperationalError},
718717
max_attempts=max_attempts)
719718

720-
def start(self, params=[], wait=True):
719+
def start(self, params=None, wait: bool = True) -> 'PostgresNode':
721720
"""
722-
Starts the PostgreSQL node using pg_ctl if node has not been started.
721+
Starts the PostgreSQL node using pg_ctl if the node has not been started.
723722
By default, it waits for the operation to complete before returning.
724723
Optionally, it can return immediately without waiting for the start operation
725724
to complete by setting the `wait` parameter to False.
@@ -731,45 +730,62 @@ def start(self, params=[], wait=True):
731730
Returns:
732731
This instance of :class:`.PostgresNode`.
733732
"""
733+
if params is None:
734+
params = []
734735
if self.is_started:
735736
return self
736737

737738
_params = [
738-
self._get_bin_path("pg_ctl"),
739-
"-D", self.data_dir,
740-
"-l", self.pg_log_file,
741-
"-w" if wait else '-W', # --wait or --no-wait
742-
"start"
743-
] + params # yapf: disable
739+
self._get_bin_path("pg_ctl"),
740+
"-D", self.data_dir,
741+
"-l", self.pg_log_file,
742+
"-w" if wait else '-W', # --wait or --no-wait
743+
"start"
744+
] + params # yapf: disable
744745

745-
startup_retries = 5
746-
while True:
746+
max_retries = 5
747+
sleep_interval = 5 # seconds
748+
749+
for attempt in range(max_retries):
747750
try:
748751
exit_status, out, error = execute_utility(_params, self.utils_log_file, verbose=True)
749752
if error and 'does not exist' in error:
750753
raise Exception
754+
break # Exit the loop if successful
751755
except Exception as e:
752-
files = self._collect_special_files()
753-
if any(len(file) > 1 and 'Is another postmaster already '
754-
'running on port' in file[1].decode() for
755-
file in files):
756-
logging.warning("Detected an issue with connecting to port {0}. "
757-
"Trying another port after a 5-second sleep...".format(self.port))
758-
self.port = reserve_port()
759-
options = {'port': str(self.port)}
760-
self.set_auto_conf(options)
761-
startup_retries -= 1
762-
time.sleep(5)
763-
continue
764-
765-
msg = 'Cannot start node'
766-
raise_from(StartNodeException(msg, files), e)
767-
break
756+
if self._handle_port_conflict():
757+
if attempt < max_retries - 1:
758+
logging.info(f"Retrying start operation (Attempt {attempt + 2}/{max_retries})...")
759+
time.sleep(sleep_interval)
760+
continue
761+
else:
762+
logging.error("Reached maximum retry attempts. Unable to start node.")
763+
raise StartNodeException("Cannot start node after multiple attempts",
764+
self._collect_special_files()) from e
765+
raise StartNodeException("Cannot start node", self._collect_special_files()) from e
766+
768767
self._maybe_start_logger()
769768
self.is_started = True
770769
return self
771770

772-
def stop(self, params=[], wait=True):
771+
def _handle_port_conflict(self) -> bool:
772+
"""
773+
Checks for a port conflict and attempts to resolve it by changing the port.
774+
Returns True if the port was changed, False otherwise.
775+
"""
776+
files = self._collect_special_files()
777+
if any(len(file) > 1 and 'Is another postmaster already running on port' in file[1].decode() for file in files):
778+
logging.warning(f"Port conflict detected on port {self.port}.")
779+
if self._should_free_port:
780+
logging.warning("Port reservation skipped due to _should_free_port setting.")
781+
return False
782+
self.port = reserve_port()
783+
self.set_auto_conf({'port': str(self.port)})
784+
logging.info(f"Port changed to {self.port}.")
785+
return True
786+
return False
787+
788+
def stop(self, params=None, wait=True):
773789
"""
774790
Stops the PostgreSQL node using pg_ctl if the node has been started.
775791
@@ -780,6 +796,8 @@ def stop(self, params=[], wait=True):
780796
Returns:
781797
This instance of :class:`.PostgresNode`.
782798
"""
799+
if params is None:
800+
params = []
783801
if not self.is_started:
784802
return self
785803

@@ -812,7 +830,7 @@ def kill(self, someone=None):
812830
os.kill(self.auxiliary_pids[someone][0], sig)
813831
self.is_started = False
814832

815-
def restart(self, params=[]):
833+
def restart(self, params=None):
816834
"""
817835
Restart this node using pg_ctl.
818836
@@ -823,6 +841,8 @@ def restart(self, params=[]):
823841
This instance of :class:`.PostgresNode`.
824842
"""
825843

844+
if params is None:
845+
params = []
826846
_params = [
827847
self._get_bin_path("pg_ctl"),
828848
"-D", self.data_dir,
@@ -844,7 +864,7 @@ def restart(self, params=[]):
844864

845865
return self
846866

847-
def reload(self, params=[]):
867+
def reload(self, params=None):
848868
"""
849869
Asynchronously reload config files using pg_ctl.
850870
@@ -855,6 +875,8 @@ def reload(self, params=[]):
855875
This instance of :class:`.PostgresNode`.
856876
"""
857877

878+
if params is None:
879+
params = []
858880
_params = [
859881
self._get_bin_path("pg_ctl"),
860882
"-D", self.data_dir,
@@ -1587,7 +1609,7 @@ def pgbench_table_checksums(self, dbname="postgres",
15871609
return {(table, self.table_checksum(table, dbname))
15881610
for table in pgbench_tables}
15891611

1590-
def set_auto_conf(self, options, config='postgresql.auto.conf', rm_options={}):
1612+
def set_auto_conf(self, options, config='postgresql.auto.conf', rm_options=None):
15911613
"""
15921614
Update or remove configuration options in the specified configuration file,
15931615
updates the options specified in the options dictionary, removes any options
@@ -1603,6 +1625,8 @@ def set_auto_conf(self, options, config='postgresql.auto.conf', rm_options={}):
16031625
Defaults to an empty set.
16041626
"""
16051627
# parse postgresql.auto.conf
1628+
if rm_options is None:
1629+
rm_options = {}
16061630
path = os.path.join(self.data_dir, config)
16071631

16081632
lines = self.os_ops.readlines(path)

0 commit comments

Comments
 (0)
Please sign in to comment.