def start_game(): ''' Main entry point for the application ''' cache_actions() sockets = netutil.bind_sockets(8888) #if process.task_id() == None: # tornado.process.fork_processes(-1, max_restarts = 10) server = HTTPServer(application) server.add_sockets(sockets) io_loop = IOLoop.instance() session_manager = SessionManager.Instance() if process.task_id() == None: scoring = PeriodicCallback(scoring_round, application.settings['ticks'], io_loop = io_loop) session_clean_up = PeriodicCallback(session_manager.clean_up, application.settings['clean_up_timeout'], io_loop = io_loop) scoring.start() session_clean_up.start() try: for count in range(3, 0, -1): logging.info("The game will begin in ... %d" % (count,)) sleep(1) logging.info("Good hunting!") io_loop.start() except KeyboardInterrupt: if process.task_id() == 0: print '\r[!] Shutdown Everything!' session_clean_up.stop() io_loop.stop()
def run_command_line(self): define("configuration", default="/etc/agentp/agent.conf", help="Configuration file") parse_command_line() # Register signal handler signal.signal(signal.SIGUSR1, self.signal_cb) signal.signal(signal.SIGUSR2, self.signal_cb) signal.signal(signal.SIGHUP, self.signal_cb) signal.signal(signal.SIGINT, self.signal_cb) # Reading configuration try: self.config = Configuration.from_file( options.configuration).configure() logging.info('Reading configuration from %s', options.configuration) except IOError: print('Configuration file "%s" does not exists.' % options.configuration) raise SystemExit(1) default_config = { 'delay': timedelta(seconds=10), 'timeout': timedelta(seconds=60) } default_config.update({ 'delay': self.config.get('delay', default_config['delay']), 'timeout': self.config.get('timeout', default_config['timeout']) }) # Forking workers = self.config.get('workers', None) if workers == 1 or workers == 'none' or not workers: pass else: process.fork_processes(int(workers) if workers != 'auto' else 0) # Defining IOLoop self.io_loop = IOLoop.current() # Configuring backends # Configuring agents if process.task_id() == 0 or not process.task_id(): for agent in self.config.agents: if isinstance(agent, str): self.io_loop.add_callback(self.configure_agent, agent, **default_config) elif isinstance(agent, dict) and 'module' in agent: self.io_loop.add_callback( self.configure_agent, agent.pop('module'), **dict(default_config.items() + agent.items())) # Starting IOLoop self.io_loop.start()
def run(self): logger.debug("starting main loop") self.handler.bind(self.port, address=None, backlog=128) self.handler.start(self.nprocs) signal.signal(signal.SIGINT, self.signal_shutdown) signal.signal(signal.SIGTERM, self.signal_shutdown) IOLoop.current().handle_callback_exception(self.handle_exception) taskid = '0' if task_id() == None else task_id() logger.debug("starting task %s (pid %d)" % (taskid, os.getpid())) IOLoop.instance().start() logger.debug("stopping main loop")
def main(): """ entry """ try: conf = __import__('conf') except ImportError as e: app_log.critical("Unable to load site config. ({})".format(e)) raise SystemExit() parse_command_line() if options.debug: app_log.setLevel(logging.DEBUG) if not options.debug: fork_processes(None) options.port += task_id() or 0 if not os.path.isdir(conf.app_path): app_log.critical("{p} isn't accessible, maybe " "create it?".format(p=conf.app_path)) raise SystemExit() app_log.debug("Starting {name} on port {port}".format(name=conf.name, port=options.port)) # initialize the application tornado.httpserver.HTTPServer(Application(options, conf)).listen(options.port, '0.0.0.0') ioloop = tornado.ioloop.IOLoop.instance() if options.debug: tornado.autoreload.start(ioloop) # enter the Tornado IO loop ioloop.start()
def main(): options.parse_command_line() _port = options.options.port _process_num = options.options.process _debug_level = options.options.debug * 10 process.fork_processes(_process_num, max_restarts=3) process_port = _port + process.task_id() process_debug = _process_num <= 1 and _debug_level < 30 print('Service Running on %d ...' % process_port) app = web.Application(( (r'/', views.base.IndexHandler), (r'/home', views.base.HomeHandler), (r'/auth/redirect', views.auth.OAuth2RedirectHandler), (r'/auth/revoke', views.auth.OAuth2RevokeHandler), (r'/auth/authorize', views.auth.OAuth2AuthorizeHandler), (r'/auth/info', views.auth.OAuth2InfoHandler), (r'/user/info', views.rest.UserInfoHandler), (r'/user/option', views.rest.UserOptionHandler), (r'/weibo/public', views.rest.WeiboPublicHandler), (r'/weibo/sync', views.rest.WeiboSyncHandler), (r'/weibo/query', views.rest.WeiboQueryHandler), (r'/weibo/redirect', views.rest.WeiboRedirectHandler), (r'/emotion/query', views.rest.EmotionQueryHandler), ), debug=process_debug, cookie_secret=setting.COOKIE_SECRET) app.listen(process_port, xheaders=True) loop = ioloop.IOLoop.instance() loop.start()
def _reload_on_update(modify_times): global needs_to_reload if _reload_attempted: # We already tried to reload and it didn't work, so don't try again. return if process.task_id() is not None: # We're in a child process created by fork_processes. If child # processes restarted themselves, they'd all restart and then # all call fork_processes again. return for module in list(sys.modules.values()): # Some modules play games with sys.modules (e.g. email/__init__.py # in the standard library), and occasionally this can cause strange # failures in getattr. Just ignore anything that's not an ordinary # module. if not isinstance(module, types.ModuleType): continue path = getattr(module, "__file__", None) if not path: continue if path.endswith(".pyc") or path.endswith(".pyo"): path = path[:-1] result = _check_file(modify_times, module, path) if result is False: # If any files errored, we abort this attempt at reloading. return if result is True: # If any files had actual changes that import properly, # we'll plan to reload the next time we run with no files # erroring. needs_to_reload = True if needs_to_reload: _reload()
def set_defaults(): # type: () -> None instance = task_id() if instance is None: instance = 0 default_tags = {"instance": str(instance)} get_plugin_proxy().set_default_stats_tags(default_tags)
def tearDown(self): if task_id() is not None: # We're in a child process, and probably got to this point # via an uncaught exception. If we return now, both # processes will continue with the rest of the test suite. # Exit now so the parent process will restart the child # (since we don't have a clean way to signal failure to # the parent that won't restart) logging.error("aborting child process from tearDown") logging.shutdown() os._exit(1) super(ProcessTest, self).tearDown()
def sig_handler(self, sig, _): """ Handle the signal sent to the process :param sig: Signal set to the process :param _: Frame is not being used """ import tornado.ioloop from tornado.process import task_id tid = task_id() pid = os.getpid() if tid is None: logger.warning("main process (pid %s) caught signal: %s" % (pid, sig)) else: logger.warning("child %s (pid %s) caught signal: %s" % (tid, pid, sig)) tornado.ioloop.IOLoop.current().add_callback_from_signal(self.shutdown)
def run(self): if options.debug: app_log.setLevel(logging.DEBUG) if not options.debug: fork_processes(None) options.port += task_id() or 0 app_log.debug("Starting %s on port %s" % (cfg.platform_name, options.port)) # initialize the application tornado.httpserver.HTTPServer(Application(self.commons)).listen(options.port, '0.0.0.0') ioloop = tornado.ioloop.IOLoop.instance() if options.debug: tornado.autoreload.start(ioloop) # enter the Tornado IO loop ioloop.start()
def shutdown(self): import time import tornado.ioloop from tornado.process import task_id tid = task_id() pid = os.getpid() if tid is None: logger.info("main process (pid %s): stopping http server" % pid) else: logger.info("child %s (pid %s): stopping http server" % (tid, pid)) for key, component in iteritems(self.application.components): component.shutdown() self.http_server.stop() io_loop = tornado.ioloop.IOLoop.current() if self.MAX_WAIT_SECONDS_BEFORE_SHUTDOWN == 0: io_loop.stop() if tid is None: logger.info("main process (pid %s): application is down" % pid) else: logger.info("child %s (pid %s): application is down" % (tid, pid)) else: if tid is None: logger.info("main process (pid %s): shutdown in %s seconds " "..." % (pid, self.MAX_WAIT_SECONDS_BEFORE_SHUTDOWN)) else: logger.info("child %s (pid %s): shutdown in %s seconds ..." % (tid, pid, self.MAX_WAIT_SECONDS_BEFORE_SHUTDOWN)) deadline = time.time() + self.MAX_WAIT_SECONDS_BEFORE_SHUTDOWN def stop_loop(): now = time.time() if now < deadline: io_loop.add_timeout(now + 1, stop_loop) else: io_loop.stop() if tid is None: logger.info("main process (pid %s): application is " "down" % pid) else: logger.info("child %s (pid %s): application is down" % (tid, pid)) stop_loop()
def test_multi_process(self): self.assertFalse(IOLoop.initialized()) port = get_unused_port() def get_url(path): return "http://127.0.0.1:%d%s" % (port, path) sockets = bind_sockets(port, "127.0.0.1") # ensure that none of these processes live too long signal.alarm(5) # master process try: id = fork_processes(3, max_restarts=3) except SystemExit, e: # if we exit cleanly from fork_processes, all the child processes # finished with status 0 self.assertEqual(e.code, 0) self.assertTrue(task_id() is None) for sock in sockets: sock.close() signal.alarm(0) return
def run(self): if options.debug: app_log.setLevel(logging.DEBUG) if not options.debug: fork_processes(None) options.port += task_id() or 0 app_log.debug("Starting %s on port %s" % ('tornado skeleton', options.port)) # initialize the application tornado.httpserver.HTTPServer(Application(self.commons)).listen( options.port, '0.0.0.0') ioloop = tornado.ioloop.IOLoop.instance() if options.debug: tornado.autoreload.start(ioloop) # enter the Tornado IO loop ioloop.start()
def __init__(self, entries, timeout, max_clients): assert entries task_id = process.task_id() if options.multi_processes == -1: process_num = 1 elif options.multi_processes == 0: process_num = process.cpu_count() else: process_num = options.multi_processes self._io_loop = ioloop.IOLoop() self._client = httpclient.AsyncHTTPClient(self._io_loop, max_clients=max_clients) self.timeout = timeout self.max_clients = max_clients self.requests = dict([(self.get_request(e), e) for e in entries]) self.partial_requests = self.requests.keys()[task_id::process_num] self.count = len(self.partial_requests)
def main(): options.parse_command_line() port = options.options.port fork = options.options.fork settings.configure('PROCESS', fork) settings.configure('PORT_GROUP', range(port, port + fork)) process.fork_processes(fork, max_restarts=10) settings.configure('PORT', port + process.task_id()) # settings.configure('PORT', port) app = web.Application( handlers=urls, #逻辑指定 **SETTINGS #路径指定 ) app.listen(settings.port, xheaders=True) loop = ioloop.IOLoop.instance() loop.start()
def run(self): self.server = tornado.httpserver.HTTPServer(self.application) self.server.bind(port=self.port) self.server.start(self.process_num) id = task_id() #多进程并不是多线程,需要考虑日志半夜切分问题,所以根据进程记录区分日志。 if id != None: log_base_config(LOG_NAME, "{}/{}/{}".format(LOG_DIR, id, LOG_FILE), level=logging.INFO) #延后加载,否则tensoflow 产生冲突 self.text_process.init() self.text_process.process('') else: log_base_config(LOG_NAME, "{}/{}".format(LOG_DIR, LOG_FILE)) self.text_process.init() self.text_process.process('') tornado.ioloop.IOLoop.current().start()
def after_fork_init(ioloop, app): """ 如果多线程模式, 那么 redis 和 mysql 的连接池创建 应该是在 多线程 fork 之后, 保证不通的 python interpreter 拥有独立的资源 :param ioloop: :param app: :return: """ ## 初始化连接 ioloop.run_until_complete(init_db(app)) # task ID 可以认为是 tornado 进程编号 t_id = task_id() t_id = t_id if t_id else 0 # 初始化 web 记录日志 configure_tornado_logger(app.settings["ACC_LOG_PATH"], app.settings["LOG_ROTATE_DAY"], app.settings["LOG_BACKUP"], name="tornado.access", debug=app.settings["DEBUG"]) configure_tornado_logger(app.settings["APP_LOG_PATH"], app.settings["LOG_ROTATE_DAY"], app.settings["LOG_BACKUP"], name="tornado.application", debug=app.settings["DEBUG"]) configure_tornado_logger(app.settings["GEN_LOG_PATH"], app.settings["LOG_ROTATE_DAY"], app.settings["LOG_BACKUP"], name="tornado.general", debug=app.settings["DEBUG"]) # 这里保证缓存只在一个进程中进行,如果不是 multiple fork 模式的话, # 0 号进程负责缓存任务, 如果是多进程模式, 那么还是由编号 0 的进程 # 任务执行缓存任务 if t_id == 0: ioloop.create_task(period_health_check(ioloop, app))
def _reload_on_update(modify_times): if _reload_attempted: # We already tried to reload and it didn't work, so don't try again. return if process.task_id() is not None: # We're in a child process created by fork_processes. If child # processes restarted themselves, they'd all restart and then # all call fork_processes again. return for module in list(sys.modules.values()): # Some modules play games with sys.modules (e.g. email/__init__.py # in the standard library), and occasionally this can cause strange # failures in getattr. Just ignore anything that's not an ordinary # module. if not isinstance(module, types.ModuleType): continue path = getattr(module, "__file__", None) if not path: continue if path.endswith(".pyc") or path.endswith(".pyo"): path = path[:-1] _check_file(modify_times, path) for path in _watched_files: _check_file(modify_times, path)
def _reload_on_update(modify_times): if _reload_attempted: # We already tried to reload and it didn't work, so don't try again. return if process.task_id() is not None: # We're in a child process created by fork_processes. If child # processes restarted themselves, they'd all restart and then # all call fork_processes again. return for module in sys.modules.values(): # Some modules play games with sys.modules (e.g. email/__init__.py # in the standard library), and occasionally this can cause strange # failures in getattr. Just ignore anything that's not an ordinary # module. if not isinstance(module, types.ModuleType): continue path = getattr(module, "__file__", None) if not path: continue if path.endswith(".pyc") or path.endswith(".pyo"): path = path[:-1] _check_file(modify_times, path) for path in _watched_files: _check_file(modify_times, path)
def main(): try: options.parse_command_line() port = options.options.port fork = options.options.fork setting['PROCESS'] = fork setting['PORT_GROUP'] = range(port, port + fork) process.fork_processes(fork, max_restarts=10) setting['PORT'] = port + process.task_id() app = web.Application( handlers=urls, **SETTINGS ) app.listen(setting['PORT'], xheaders=True) loop = ioloop.IOLoop.instance() loop.start() except Exception, e: logger.error(traceback.format_exc(e))
def tornado_bidder_run(): """runs httpapi bidder agent""" # bind tcp port to launch processes on requests sockets = netutil.bind_sockets(CONFIG_OBJ["Bidder"]["Port"]) # fork working processes process.fork_processes(0) # Tornado app implementation app = Application([url(r"/", TornadoFixPriceBidAgentRequestHandler)]) # start http servers and attach the web app to it server = httpserver.HTTPServer(app) server.add_sockets(sockets) # perform following actions only in the parent process process_counter = process.task_id() if (process_counter == 0): # run dummy ad server adserver_win = Application([url(r"/", TornadoDummyRequestHandler)]) winport = CONFIG_OBJ["Bidder"]["Win"] adserver_win.listen(winport) adserver_evt = Application([url(r"/", TornadoDummyRequestHandler)]) evtport = CONFIG_OBJ["Bidder"]["Event"] adserver_evt.listen(evtport) # --instantiate budget pacer pacer = BudgetControl() pacer.start(CONFIG_OBJ) # add periodic event to call pacer PeriodicCallback(pacer.http_request, CONFIG_OBJ["Banker"]["Period"]).start() # main io loop. it will loop waiting for requests IOLoop.instance().start()
def tornado_bidder_run(): """runs httpapi bidder agent""" # bind tcp port to launch processes on requests sockets = netutil.bind_sockets(CONFIG_OBJ["Bidder"]["Port"]) # fork working processes process.fork_processes(0) # Tornado app implementation app = Application([url(r"/", TornadoFixPriceBidAgentRequestHandler)]) # start http servers and attach the web app to it server = httpserver.HTTPServer(app) server.add_sockets(sockets) # perform following actions only in the parent process process_counter = process.task_id() if process_counter == 0: # run dummy ad server adserver_win = Application([url(r"/", TornadoDummyRequestHandler)]) winport = CONFIG_OBJ["Bidder"]["Win"] adserver_win.listen(winport) adserver_evt = Application([url(r"/", TornadoDummyRequestHandler)]) evtport = CONFIG_OBJ["Bidder"]["Event"] adserver_evt.listen(evtport) # --instantiate budget pacer pacer = BudgetControl() pacer.start(CONFIG_OBJ) # add periodic event to call pacer PeriodicCallback(pacer.http_request, CONFIG_OBJ["Banker"]["Period"]).start() # main io loop. it will loop waiting for requests IOLoop.instance().start()
# state can store objects that get updated asyncronously and are needed everywhere shared_system_state = MyApp(config) # multiple request handlers, sharing the same state tornado_app_config = tornado.web.Application([ ( r"/some_path", MyRequestHandler, dict(config=config, state=shared_system_state) ), ]) # listen on the configured port, default to 8888 if not specified sockets = bind_sockets(config.get('port', 8888)) # multi-process tornado. auto forks for every core you have fork_processes() # grab the task id so you can use it to refer to unique sub processes shared_system_state.task_id = task_id() # set the server's application handler server = HTTPServer(tornado_app_config) server.add_sockets(sockets) # create the io loop main_loop = tornado.ioloop.IOLoop.instance() # can add multiple asyncronous periodic loops async_loop = tornado.ioloop.PeriodicCallback( shared_system_state.async_function, config.conf['async_loop_period'], io_loop=main_loop ) async_loop.start() main_loop.start()
def test_multi_process(self): self.assertFalse(IOLoop.initialized()) port = get_unused_port() def get_url(path): return "http://127.0.0.1:%d%s" % (port, path) sockets = bind_sockets(port, "127.0.0.1") # ensure that none of these processes live too long signal.alarm(5) # master process id = fork_processes(3, max_restarts=3) if id is None: # back in the master process; everything worked! self.assertTrue(task_id() is None) for sock in sockets: sock.close() signal.alarm(0) return signal.alarm(5) # child process try: if id in (0, 1): signal.alarm(5) self.assertEqual(id, task_id()) server = HTTPServer(self.get_app()) server.add_sockets(sockets) IOLoop.instance().start() elif id == 2: signal.alarm(5) self.assertEqual(id, task_id()) for sock in sockets: sock.close() client = HTTPClient() def fetch(url, fail_ok=False): try: return client.fetch(get_url(url)) except HTTPError as e: if not (fail_ok and e.code == 599): raise # Make two processes exit abnormally fetch("/?exit=2", fail_ok=True) fetch("/?exit=3", fail_ok=True) # They've been restarted, so a new fetch will work int(fetch("/").body) # Now the same with signals # Disabled because on the mac a process dying with a signal # can trigger an "Application exited abnormally; send error # report to Apple?" prompt. #fetch("/?signal=%d" % signal.SIGTERM, fail_ok=True) #fetch("/?signal=%d" % signal.SIGABRT, fail_ok=True) #int(fetch("/").body) # Now kill them normally so they won't be restarted fetch("/?exit=0", fail_ok=True) # One process left; watch it's pid change pid = int(fetch("/").body) fetch("/?exit=4", fail_ok=True) pid2 = int(fetch("/").body) self.assertNotEqual(pid, pid2) # Kill the last one so we shut down cleanly fetch("/?exit=0", fail_ok=True) os._exit(0) except Exception: logging.error("exception in child process %d", id, exc_info=True) raise
def sigterm_handler(signum, frame): print >> sys.stderr, "%s: SIGTERM received. Exiting..." % \ task_id(process.task_id()) sys.exit(0)
def hello(): cid = task_id() cid = "#%s" % cid if cid != None else "MAIN" user_ip = request.environ.get("REMOTE_ADDR", "Unknown") print "%s: serving a request from %s" % (cid, user_ip) return "Hello %s! from %s" % (user_ip, cid)
#!/usr/bin/env python3 from tornado.ioloop import IOLoop from tornado.process import task_id, fork_processes from tornado.web import Application, RequestHandler class MainHandler(RequestHandler): def get(self): self.write('Hello, I am ID {}\n'.format(task_id())) class CrashHandler(RequestHandler): def get(self): self.write('Crashing ID {}!\n'.format(task_id())) IOLoop.current().stop() if __name__ == '__main__': app = Application([ (r'/', MainHandler), (r'/crash', CrashHandler), ]) fork_processes(6) app.listen(8080 + task_id(), address='127.0.0.1') IOLoop.current().start()
app = web.Application(( (r'/', views.base.IndexHandler), (r'/home', views.base.HomeHandler), (r'/auth/redirect', views.auth.OAuth2RedirectHandler), (r'/auth/revoke', views.auth.OAuth2RevokeHandler), (r'/auth/authorize', views.auth.OAuth2AuthorizeHandler), (r'/auth/info', views.auth.OAuth2InfoHandler), (r'/user/info', views.rest.UserInfoHandler), (r'/user/option', views.rest.UserOptionHandler), (r'/weibo/public', views.rest.WeiboPublicHandler), (r'/weibo/sync', views.rest.WeiboSyncHandler), (r'/weibo/query', views.rest.WeiboQueryHandler), (r'/weibo/redirect', views.rest.WeiboRedirectHandler), (r'/emotion/query', views.rest.EmotionQueryHandler), ), debug=process_debug, cookie_secret=setting.COOKIE_SECRET) app.listen(process_port, xheaders=True) loop = ioloop.IOLoop.instance() loop.start() if __name__ == '__main__': try: main() except KeyboardInterrupt: if not process.task_id() is None: ioloop.IOLoop.current().stop() else: print('Capture KeyboardInterrupt. Try to stop service ...')
return None def main(): logging.basicConfig( format= '[%(levelname)s %(asctime)s %(name)s %(module)s:%(lineno)d] %(message)s', datefmt='%Y-%m-%d %H:%M:%S') parse_options() app = Application() http_server = HTTPServer(app, xheaders=True) http_server.bind(int(options.port), options.host) try: http_server.start(options.instances) except KeyboardInterrupt, e: logging.warn('parent exiting!') sys.exit(0) try: main_loop = IOLoop.instance() main_loop.start() except: logging.warn('child process exit! task_id: {}'.format( process.task_id())) if __name__ == '__main__': main()
def get(self): self.write('Crashing ID {}!\n'.format(task_id())) IOLoop.current().stop()
def test_multi_process(self): # This test doesn't work on twisted because we use the global # reactor and don't restore it to a sane state after the fork # (asyncio has the same issue, but we have a special case in # place for it). skip_if_twisted() with ExpectLog(gen_log, "(Starting .* processes|child .* exited|uncaught exception)"): sock, port = bind_unused_port() def get_url(path): return "http://127.0.0.1:%d%s" % (port, path) # ensure that none of these processes live too long signal.alarm(5) # master process try: id = fork_processes(3, max_restarts=3) self.assertTrue(id is not None) signal.alarm(5) # child processes except SystemExit as e: # if we exit cleanly from fork_processes, all the child processes # finished with status 0 self.assertEqual(e.code, 0) self.assertTrue(task_id() is None) sock.close() return try: if asyncio is not None: # Reset the global asyncio event loop, which was put into # a broken state by the fork. asyncio.set_event_loop(asyncio.new_event_loop()) if id in (0, 1): self.assertEqual(id, task_id()) server = HTTPServer(self.get_app()) server.add_sockets([sock]) IOLoop.current().start() elif id == 2: self.assertEqual(id, task_id()) sock.close() # Always use SimpleAsyncHTTPClient here; the curl # version appears to get confused sometimes if the # connection gets closed before it's had a chance to # switch from writing mode to reading mode. client = HTTPClient(SimpleAsyncHTTPClient) def fetch(url, fail_ok=False): try: return client.fetch(get_url(url)) except HTTPError as e: if not (fail_ok and e.code == 599): raise # Make two processes exit abnormally fetch("/?exit=2", fail_ok=True) fetch("/?exit=3", fail_ok=True) # They've been restarted, so a new fetch will work int(fetch("/").body) # Now the same with signals # Disabled because on the mac a process dying with a signal # can trigger an "Application exited abnormally; send error # report to Apple?" prompt. # fetch("/?signal=%d" % signal.SIGTERM, fail_ok=True) # fetch("/?signal=%d" % signal.SIGABRT, fail_ok=True) # int(fetch("/").body) # Now kill them normally so they won't be restarted fetch("/?exit=0", fail_ok=True) # One process left; watch it's pid change pid = int(fetch("/").body) fetch("/?exit=4", fail_ok=True) pid2 = int(fetch("/").body) self.assertNotEqual(pid, pid2) # Kill the last one so we shut down cleanly fetch("/?exit=0", fail_ok=True) os._exit(0) except Exception: logging.error("exception in child process %d", id, exc_info=True) raise
def test_multi_process(self): self.assertFalse(IOLoop.initialized()) port = get_unused_port() def get_url(path): return "http://127.0.0.1:%d%s" % (port, path) sockets = bind_sockets(port, "127.0.0.1") # ensure that none of these processes live too long signal.alarm(5) # master process id = fork_processes(3, max_restarts=3) if id is None: # back in the master process; everything worked! self.assertTrue(task_id() is None) for sock in sockets: sock.close() signal.alarm(0) return signal.alarm(5) # child process try: if id in (0, 1): signal.alarm(5) self.assertEqual(id, task_id()) server = HTTPServer(self.get_app()) server.add_sockets(sockets) IOLoop.instance().start() elif id == 2: signal.alarm(5) self.assertEqual(id, task_id()) for sock in sockets: sock.close() client = HTTPClient() def fetch(url, fail_ok=False): try: return client.fetch(get_url(url)) except HTTPError, e: if not (fail_ok and e.code == 599): raise # Make two processes exit abnormally fetch("/?exit=2", fail_ok=True) fetch("/?exit=3", fail_ok=True) # They've been restarted, so a new fetch will work int(fetch("/").body) # Now the same with signals # Disabled because on the mac a process dying with a signal # can trigger an "Application exited abnormally; send error # report to Apple?" prompt. #fetch("/?signal=%d" % signal.SIGTERM, fail_ok=True) #fetch("/?signal=%d" % signal.SIGABRT, fail_ok=True) #int(fetch("/").body) # Now kill them normally so they won't be restarted fetch("/?exit=0", fail_ok=True) # One process left; watch it's pid change pid = int(fetch("/").body) fetch("/?exit=4", fail_ok=True) pid2 = int(fetch("/").body) self.assertNotEqual(pid, pid2) # Kill the last one so we shut down cleanly fetch("/?exit=0", fail_ok=True) os._exit(0) except Exception: logging.error("exception in child process %d", id, exc_info=True) raise
def get(self): self.write('Hello, I am ID {}\n'.format(task_id()))
def handle_stream(self, stream, addr): self.stream = stream print "====== Handle new stream from ======" print process.task_id(), addr self.handle_request(stream)
def get(self, *args, **kwargs): ''' Display the default user page ''' user = User.by_user_name(self.session.data['user_name']) logging.info("Home of %s, task id is %s" % (user.user_name, str(process.task_id()))) self.render('user/home.html', user = user)
import signal def task_id(tid): return "#%s" % tid if tid != None else "MAIN" def sigterm_handler(signum, frame): print >> sys.stderr, "%s: SIGTERM received. Exiting..." % \ task_id(process.task_id()) sys.exit(0) signal.signal(signal.SIGTERM, sigterm_handler) if __name__ == "__main__": sockets = [bind_unix_socket(sys.argv[1] if len(sys.argv)>1 else None)] if "fork" in os.__dict__: print "%s: %s cpu(s) detected, spawning..." % \ (task_id(process.task_id()), process.cpu_count()) child_id = task_id(process.fork_processes(0)) if child_id != "MAIN": print "%s: listen on %s" % (child_id, sockets) else: print "%s: All child processes have exited normally. Exiting..." % \ child_id sys.exit(0) else: print "forking not available, use single-process." http_server = HTTPServer(WSGIContainer(app)) http_server.add_sockets(sockets) IOLoop.instance().start()
def test_multi_process(self): # This test can't work on twisted because we use the global reactor # and have no way to get it back into a sane state after the fork. skip_if_twisted() with ExpectLog(gen_log, "(Starting .* processes|child .* exited|uncaught exception)"): self.assertFalse(IOLoop.initialized()) sock, port = bind_unused_port() def get_url(path): return "http://127.0.0.1:%d%s" % (port, path) # ensure that none of these processes live too long signal.alarm(5) # master process try: id = fork_processes(3, max_restarts=3) self.assertTrue(id is not None) signal.alarm(5) # child processes except SystemExit as e: # if we exit cleanly from fork_processes, all the child processes # finished with status 0 self.assertEqual(e.code, 0) self.assertTrue(task_id() is None) sock.close() return try: if id in (0, 1): self.assertEqual(id, task_id()) server = HTTPServer(self.get_app()) server.add_sockets([sock]) IOLoop.current().start() elif id == 2: self.assertEqual(id, task_id()) sock.close() # Always use SimpleAsyncHTTPClient here; the curl # version appears to get confused sometimes if the # connection gets closed before it's had a chance to # switch from writing mode to reading mode. client = HTTPClient(SimpleAsyncHTTPClient) def fetch(url, fail_ok=False): try: return client.fetch(get_url(url)) except HTTPError as e: if not (fail_ok and e.code == 599): raise # Make two processes exit abnormally fetch("/?exit=2", fail_ok=True) fetch("/?exit=3", fail_ok=True) # They've been restarted, so a new fetch will work int(fetch("/").body) # Now the same with signals # Disabled because on the mac a process dying with a signal # can trigger an "Application exited abnormally; send error # report to Apple?" prompt. # fetch("/?signal=%d" % signal.SIGTERM, fail_ok=True) # fetch("/?signal=%d" % signal.SIGABRT, fail_ok=True) # int(fetch("/").body) # Now kill them normally so they won't be restarted fetch("/?exit=0", fail_ok=True) # One process left; watch it's pid change pid = int(fetch("/").body) fetch("/?exit=4", fail_ok=True) pid2 = int(fetch("/").body) self.assertNotEqual(pid, pid2) # Kill the last one so we shut down cleanly fetch("/?exit=0", fail_ok=True) os._exit(0) except Exception: logging.error("exception in child process %d", id, exc_info=True) raise
class ProcessTest(LogTrapTestCase): def get_app(self): class ProcessHandler(RequestHandler): def get(self): if self.get_argument("exit", None): # must use os._exit instead of sys.exit so unittest's # exception handler doesn't catch it os._exit(int(self.get_argument("exit"))) if self.get_argument("signal", None): os.kill(os.getpid(), int(self.get_argument("signal"))) self.write(str(os.getpid())) return Application([("/", ProcessHandler)]) def tearDown(self): if task_id() is not None: # We're in a child process, and probably got to this point # via an uncaught exception. If we return now, both # processes will continue with the rest of the test suite. # Exit now so the parent process will restart the child # (since we don't have a clean way to signal failure to # the parent that won't restart) logging.error("aborting child process from tearDown") logging.shutdown() os._exit(1) super(ProcessTest, self).tearDown() def test_multi_process(self): self.assertFalse(IOLoop.initialized()) port = get_unused_port() def get_url(path): return "http://127.0.0.1:%d%s" % (port, path) sockets = bind_sockets(port, "127.0.0.1") # ensure that none of these processes live too long signal.alarm(5) # master process try: id = fork_processes(3, max_restarts=3) except SystemExit, e: # if we exit cleanly from fork_processes, all the child processes # finished with status 0 self.assertEqual(e.code, 0) self.assertTrue(task_id() is None) for sock in sockets: sock.close() signal.alarm(0) return signal.alarm(5) # child process try: if id in (0, 1): signal.alarm(5) self.assertEqual(id, task_id()) server = HTTPServer(self.get_app()) server.add_sockets(sockets) IOLoop.instance().start() elif id == 2: signal.alarm(5) self.assertEqual(id, task_id()) for sock in sockets: sock.close() # Always use SimpleAsyncHTTPClient here; the curl # version appears to get confused sometimes if the # connection gets closed before it's had a chance to # switch from writing mode to reading mode. client = HTTPClient(SimpleAsyncHTTPClient) def fetch(url, fail_ok=False): try: return client.fetch(get_url(url)) except HTTPError, e: if not (fail_ok and e.code == 599): raise # Make two processes exit abnormally fetch("/?exit=2", fail_ok=True) fetch("/?exit=3", fail_ok=True) # They've been restarted, so a new fetch will work int(fetch("/").body) # Now the same with signals # Disabled because on the mac a process dying with a signal # can trigger an "Application exited abnormally; send error # report to Apple?" prompt. #fetch("/?signal=%d" % signal.SIGTERM, fail_ok=True) #fetch("/?signal=%d" % signal.SIGABRT, fail_ok=True) #int(fetch("/").body) # Now kill them normally so they won't be restarted fetch("/?exit=0", fail_ok=True) # One process left; watch it's pid change pid = int(fetch("/").body) fetch("/?exit=4", fail_ok=True) pid2 = int(fetch("/").body) self.assertNotEqual(pid, pid2) # Kill the last one so we shut down cleanly fetch("/?exit=0", fail_ok=True) os._exit(0) except Exception: logging.error("exception in child process %d", id, exc_info=True) raise
def shut_down(self): taskid = '0' if task_id() == None else task_id() logger.debug("stopping task %s" % taskid) self.handler.stop() IOLoop.current().stop()