Skip to content

Commit cfa5c79

Browse files
VitaliyaIoffeylobankov
authored andcommitted
Add timeout for starting tarantool server
When a tarantool server starts, it waits for a special pattern in the log file to proceed. If there is no pattern present, the server hangs. After the test timeout (TEST_TIMEOUT) runs out, the test fails. This patch adds the `--server-start-timeout` option to test-run (by default it equals to 90 seconds). Now when the server hangs and the time (SERVER_START_TIMEOUT) runs out, a comprehensible exception is raised with the message that the server failed to start within the timeout. Fixes: #276
1 parent 0fd83f6 commit cfa5c79

File tree

3 files changed

+48
-16
lines changed

3 files changed

+48
-16
lines changed

lib/options.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,15 @@ def __init__(self):
213213
Such files created by workers in the "var/reproduce" directory.
214214
Note: The option works now only with parallel testing.""")
215215

216+
parser.add_argument(
217+
"--server-start-timeout",
218+
dest="server_start_timeout",
219+
default=env_int('SERVER_START_TIMEOUT', 90),
220+
type=int,
221+
help="""Break the server process with kill signal if the server
222+
starts longer than this amount of seconds. Default: 90 [seconds]."""
223+
)
224+
216225
parser.add_argument(
217226
"--test-timeout",
218227
dest="test_timeout",

lib/tarantool_server.py

Lines changed: 37 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -414,8 +414,15 @@ def execute(self, server):
414414

415415

416416
class TarantoolStartError(OSError):
417-
def __init__(self, name=None):
417+
def __init__(self, name=None, timeout=None):
418418
self.name = name
419+
self.timeout = timeout
420+
421+
def __str__(self):
422+
message = '[Instance "{}"] Failed to start'.format(self.name)
423+
if self.timeout:
424+
return "\n{} within {} seconds\n".format(message, self.timeout)
425+
return "\n{}\n".format(message)
419426

420427

421428
class TarantoolLog(object):
@@ -444,16 +451,18 @@ def seek_once(self, msg):
444451
if pos != -1:
445452
return pos
446453

447-
def seek_wait(self, msg, proc=None, name=None):
448-
while True:
454+
def seek_wait(self, msg, proc=None, name=None, deadline=None):
455+
while not deadline or time.time() < deadline:
449456
if os.path.exists(self.path):
450457
break
451458
gevent.sleep(0.001)
459+
else:
460+
return False
452461

453462
with open(self.path, 'r') as f:
454463
f.seek(self.log_begin, os.SEEK_SET)
455464
cur_pos = self.log_begin
456-
while True:
465+
while not deadline or time.time() < deadline:
457466
if not (proc is None):
458467
if not (proc.poll() is None):
459468
raise TarantoolStartError(name)
@@ -463,8 +472,9 @@ def seek_wait(self, msg, proc=None, name=None):
463472
f.seek(cur_pos, os.SEEK_SET)
464473
continue
465474
if re.findall(msg, log_str):
466-
return
475+
return True
467476
cur_pos = f.tell()
477+
return False
468478

469479

470480
class TarantoolServer(Server):
@@ -873,9 +883,10 @@ def start(self, silent=True, wait=True, wait_load=True, rais=True, args=[],
873883
self.crash_detector.start()
874884

875885
if wait:
886+
deadline = time.time() + Options().args.server_start_timeout
876887
try:
877-
self.wait_until_started(wait_load)
878-
except TarantoolStartError:
888+
self.wait_until_started(wait_load, deadline)
889+
except TarantoolStartError as err:
879890
# Python tests expect we raise an exception when non-default
880891
# server fails
881892
if self.crash_expected:
@@ -884,9 +895,7 @@ def start(self, silent=True, wait=True, wait_load=True, rais=True, args=[],
884895
self.current_test.is_crash_reported):
885896
if self.current_test:
886897
self.current_test.is_crash_reported = True
887-
color_stdout('\n[Instance "{0.name}"] Tarantool server '
888-
'failed to start\n'.format(self),
889-
schema='error')
898+
color_stdout(err, schema='error')
890899
self.print_log(15)
891900
# Raise exception when caller ask for it (e.g. in case of
892901
# non-default servers)
@@ -1084,7 +1093,19 @@ def kill_old_server(self, silent=True):
10841093
self.wait_until_stopped(pid)
10851094
return True
10861095

1087-
def wait_until_started(self, wait_load=True):
1096+
def wait_load(self, deadline):
1097+
"""Wait until the server log file is matched the entry pattern
1098+
1099+
If the entry pattern couldn't be found in a log file until a timeout
1100+
is up, it will raise a TarantoolStartError exception.
1101+
"""
1102+
msg = 'entering the event loop|will retry binding|hot standby mode'
1103+
p = self.process if not self.gdb and not self.lldb else None
1104+
if not self.logfile_pos.seek_wait(msg, p, self.name, deadline):
1105+
raise TarantoolStartError(
1106+
self.name, Options().args.server_start_timeout)
1107+
1108+
def wait_until_started(self, wait_load=True, deadline=None):
10881109
""" Wait until server is started.
10891110
10901111
Server consists of two parts:
@@ -1095,12 +1116,9 @@ def wait_until_started(self, wait_load=True):
10951116
color_log('DEBUG: [Instance {}] Waiting until started '
10961117
'(wait_load={})\n'.format(self.name, str(wait_load)),
10971118
schema='info')
1098-
10991119
if wait_load:
1100-
msg = 'entering the event loop|will retry binding|hot standby mode'
1101-
p = self.process if not self.gdb and not self.lldb else None
1102-
self.logfile_pos.seek_wait(msg, p, self.name)
1103-
while True:
1120+
self.wait_load(deadline)
1121+
while not deadline or time.time() < deadline:
11041122
try:
11051123
temp = AdminConnection('localhost', self.admin.port)
11061124
if not wait_load:
@@ -1126,6 +1144,9 @@ def wait_until_started(self, wait_load=True):
11261144
gevent.sleep(0.1)
11271145
continue
11281146
raise
1147+
else:
1148+
raise TarantoolStartError(
1149+
self.name, Options().args.server_start_timeout)
11291150

11301151
def wait_until_stopped(self, pid):
11311152
while True:

test-run.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ def main_loop_parallel():
9191

9292
color_stdout("Timeout options:\n", schema='tr_text')
9393
color_stdout('-' * 19, "\n", schema='separator')
94+
color_stdout("SERVER_START_TIMEOUT:" . ljust(26) + "{}\n" .
95+
format(args.server_start_timeout), schema='tr_text')
9496
color_stdout("REPLICATION_SYNC_TIMEOUT:" . ljust(26) + "{}\n" .
9597
format(args.replication_sync_timeout), schema='tr_text')
9698
color_stdout("TEST_TIMEOUT:" . ljust(26) + "{}\n" .

0 commit comments

Comments
 (0)