#!/usr/bin/env python3 import os import sys import time import signal import subprocess import re # check for the venv from lib import sanity_check sanity_check.check_venv(__file__) from typing import IO # TODO: Convert this to use scripts/lib/queue_workers.py TOOLS_DIR = os.path.dirname(os.path.abspath(__file__)) successful_worker_launches = [ '[process_queue] 20 queue worker threads were launched', ] def check_worker_launch(logfile_name): # type: (str) -> bool def check(content): # type: (str) -> bool flag = True for entry in successful_worker_launches: flag = flag and entry in content return flag failed = True log_output = [] print("Polling logfile", end='') logfile = open(logfile_name, 'rb', buffering=0) # Attempt to poll the log file for 60 sec. to see if all worker threads are launched. for i in range(200): time.sleep(0.3) sys.stdout.write('.') sys.stdout.flush() new_data = logfile.read().decode() if new_data: log_output.append(new_data) if check(''.join(log_output)): failed = False break sys.stdout.write('\n') logfile.close() if not failed: print('Worker threads launched successfully') else: print('Error in server startup. Dumping logs') print(''.join(log_output)) return failed if __name__ == '__main__': print('\nStarting Development Server') logfile_name = '/tmp/run-dev-output' logfile = open(logfile_name, 'wb', buffering=0) args = ["{}/run-dev.py".format(TOOLS_DIR)] run_dev = subprocess.Popen(args, stdout=logfile, stderr=subprocess.STDOUT) failed = check_worker_launch(logfile_name) if failed: run_dev.send_signal(signal.SIGINT) run_dev.wait() logfile.close() sys.exit(1) # In dev. environment, queues are run through Django's autoreload code. The # autoreload code of Django works by looping over the files associated with # all the loaded modules. This loop is run after every 1 second. If the # file is found for the first time by the loop, it is assumed that the # file is new and is not modified between the time it is loaded and is # checked by the loop. This assumption is the source of a race condition. # We can either implement a more sensitive version of the loop or we can # just allow enough time to the Django loop to touch every file at least # once. time.sleep(1.3) # Removing all data from the server log file. logfile.truncate(0) logfile.seek(0) print("Attempting to modify a file") subprocess.call(['touch', 'zerver/lib/actions.py']) failed = check_worker_launch(logfile_name) run_dev.send_signal(signal.SIGINT) run_dev.wait() logfile.close() if failed: sys.exit(1)