implemented stop signal using pg_ctl for non posix systems (#1342)

Using pg_ctl to send stop signal for non posix os.
This commit is contained in:
Igor Yanchenko
2020-01-16 14:35:47 +01:00
committed by Alexander Kukushkin
parent 1c4d395d5a
commit 16fe180ed6
4 changed files with 35 additions and 7 deletions
+2 -1
View File
@@ -1290,7 +1290,8 @@ class Ha(object):
data_sysid = self.state_handler.sysid
if not self.sysid_valid(data_sysid):
# data directory is not empty, but no valid sysid, cluster must be broken, suggest reinit
return "data dir for the cluster is not empty, but system ID is invalid; consider doing reinitalize"
return ("data dir for the cluster is not empty, but system ID is invalid; consider doing"
"reinitialize")
if self.sysid_valid(self.cluster.initialize):
if self.cluster.initialize != data_sysid:
+3 -4
View File
@@ -516,7 +516,7 @@ class Postgresql(object):
self.set_state('stopping')
# Send signal to postmaster to stop
success = postmaster.signal_stop(mode)
success = postmaster.signal_stop(mode, self.pgcommand('pg_ctl'))
if success is not None:
if success and on_safepoint:
on_safepoint()
@@ -533,11 +533,10 @@ class Postgresql(object):
return True, True
@staticmethod
def terminate_starting_postmaster(postmaster):
def terminate_starting_postmaster(self, postmaster):
"""Terminates a postmaster that has not yet opened ports or possibly even written a pid file. Blocks
until the process goes away."""
postmaster.signal_stop('immediate')
postmaster.signal_stop('immediate', self.pgcommand('pg_ctl'))
postmaster.wait()
def _wait_for_connection_close(self, postmaster):
+15 -2
View File
@@ -22,7 +22,7 @@ logger = logging.getLogger(__name__)
STOP_SIGNALS = {
'smart': signal.SIGTERM,
'fast': signal.SIGINT,
'immediate': signal.SIGQUIT if os.name != 'nt' else signal.SIGABRT,
'immediate': signal.SIGQUIT,
}
@@ -105,7 +105,7 @@ class PostmasterProcess(psutil.Process):
except psutil.NoSuchProcess:
return None
def signal_stop(self, mode):
def signal_stop(self, mode, pg_ctl='pg_ctl'):
"""Signal postmaster process to stop
:returns None if signaled, True if process is already gone, False if error
@@ -113,6 +113,8 @@ class PostmasterProcess(psutil.Process):
if self.is_single_user:
logger.warning("Cannot stop server; single-user server is running (PID: {0})".format(self.pid))
return False
if os.name != 'posix':
return self.pg_ctl_kill(mode, pg_ctl)
try:
self.send_signal(STOP_SIGNALS[mode])
except psutil.NoSuchProcess:
@@ -123,6 +125,17 @@ class PostmasterProcess(psutil.Process):
return None
def pg_ctl_kill(self, mode, pg_ctl):
SIGNALNAME = {"smart": "TERM", "fast": "INT", "immediate": "QUIT"}[mode]
try:
status = subprocess.call([pg_ctl, "kill", SIGNALNAME, str(self.pid)])
except OSError:
return False
if status == 0:
return None
else:
return not self.is_running()
def wait_for_user_backends_to_close(self):
# These regexps are cross checked against versions PostgreSQL 9.1 .. 11
aux_proc_re = re.compile("(?:postgres:)( .*:)? (?:(?:archiver|startup|autovacuum launcher|autovacuum worker|"
+15
View File
@@ -76,6 +76,21 @@ class TestPostmasterProcess(unittest.TestCase):
self.assertEqual(proc.signal_stop('immediate'), True)
self.assertEqual(proc.signal_stop('immediate'), False)
@patch('psutil.Process.__init__', Mock())
@patch('patroni.postgresql.postmaster.os')
@patch('subprocess.call', Mock(side_effect=[0, OSError, 1]))
@patch('psutil.Process.pid', Mock(return_value=123))
@patch('psutil.Process.is_running', Mock(return_value=False))
def test_signal_stop_nt(self, mock_os):
mock_os.configure_mock(name="nt")
proc = PostmasterProcess(-123)
self.assertEqual(proc.signal_stop('immediate'), False)
proc = PostmasterProcess(123)
self.assertEqual(proc.signal_stop('immediate'), None)
self.assertEqual(proc.signal_stop('immediate'), False)
self.assertEqual(proc.signal_stop('immediate'), True)
@patch('psutil.Process.__init__', Mock())
@patch('psutil.wait_procs')
def test_wait_for_user_backends_to_close(self, mock_wait):