mirror of
https://github.com/zulip/zulip.git
synced 2025-11-03 13:33:24 +00:00
We use retry_event in queue_processors.py to handle trying on failures, without getting stuck in permanent retry loops if the event ends up leading to failure on every attempt and we just keep sending NACK to rabbitmq forever (or until the channel crashes). Tornado queues haven't been using this, but they should.
124 lines
4.9 KiB
Python
124 lines
4.9 KiB
Python
import logging
|
|
import sys
|
|
from typing import Any, Callable
|
|
|
|
from django.conf import settings
|
|
from django.core.management.base import BaseCommand, CommandError, \
|
|
CommandParser
|
|
from tornado import ioloop
|
|
from tornado.log import app_log
|
|
|
|
# We must call zerver.tornado.ioloop_logging.instrument_tornado_ioloop
|
|
# before we import anything else from our project in order for our
|
|
# Tornado load logging to work; otherwise we might accidentally import
|
|
# zerver.lib.queue (which will instantiate the Tornado ioloop) before
|
|
# this.
|
|
from zerver.tornado.ioloop_logging import instrument_tornado_ioloop
|
|
|
|
settings.RUNNING_INSIDE_TORNADO = True
|
|
instrument_tornado_ioloop()
|
|
|
|
from zerver.lib.debug import interactive_debug_listen
|
|
from zerver.tornado.application import create_tornado_application, \
|
|
setup_tornado_rabbitmq
|
|
from zerver.tornado.autoreload import start as zulip_autoreload_start
|
|
from zerver.tornado.event_queue import add_client_gc_hook, \
|
|
missedmessage_hook, get_wrapped_process_notification, setup_event_queue
|
|
from zerver.tornado.sharding import notify_tornado_queue_name
|
|
|
|
if settings.USING_RABBITMQ:
|
|
from zerver.lib.queue import get_queue_client
|
|
|
|
|
|
def handle_callback_exception(callback: Callable[..., Any]) -> None:
|
|
logging.exception("Exception in callback")
|
|
app_log.error("Exception in callback %r", callback, exc_info=True)
|
|
|
|
class Command(BaseCommand):
|
|
help = "Starts a Tornado Web server wrapping Django."
|
|
|
|
def add_arguments(self, parser: CommandParser) -> None:
|
|
parser.add_argument('addrport', nargs="?", type=str,
|
|
help='[optional port number or ipaddr:port]\n '
|
|
'(use multiple ports to start multiple servers)')
|
|
|
|
parser.add_argument('--nokeepalive', action='store_true',
|
|
dest='no_keep_alive', default=False,
|
|
help="Tells Tornado to NOT keep alive http connections.")
|
|
|
|
parser.add_argument('--noxheaders', action='store_false',
|
|
dest='xheaders', default=True,
|
|
help="Tells Tornado to NOT override remote IP with X-Real-IP.")
|
|
|
|
def handle(self, addrport: str, **options: bool) -> None:
|
|
interactive_debug_listen()
|
|
|
|
import django
|
|
from tornado import httpserver
|
|
|
|
try:
|
|
addr, port = addrport.split(':')
|
|
except ValueError:
|
|
addr, port = '', addrport
|
|
|
|
if not addr:
|
|
addr = '127.0.0.1'
|
|
|
|
if not port.isdigit():
|
|
raise CommandError("%r is not a valid port number." % (port,))
|
|
|
|
xheaders = options.get('xheaders', True)
|
|
no_keep_alive = options.get('no_keep_alive', False)
|
|
quit_command = 'CTRL-C'
|
|
|
|
if settings.DEBUG:
|
|
logging.basicConfig(level=logging.INFO,
|
|
format='%(asctime)s %(levelname)-8s %(message)s')
|
|
|
|
def inner_run() -> None:
|
|
from django.conf import settings
|
|
from django.utils import translation
|
|
translation.activate(settings.LANGUAGE_CODE)
|
|
|
|
print("Validating Django models.py...")
|
|
self.check(display_num_errors=True)
|
|
print("\nDjango version %s" % (django.get_version(),))
|
|
print("Tornado server is running at http://%s:%s/" % (addr, port))
|
|
print("Quit the server with %s." % (quit_command,))
|
|
|
|
if settings.USING_RABBITMQ:
|
|
queue_client = get_queue_client()
|
|
# Process notifications received via RabbitMQ
|
|
queue_name = notify_tornado_queue_name(int(port))
|
|
queue_client.register_json_consumer(queue_name,
|
|
get_wrapped_process_notification(queue_name))
|
|
|
|
try:
|
|
# Application is an instance of Django's standard wsgi handler.
|
|
application = create_tornado_application(int(port))
|
|
if settings.AUTORELOAD:
|
|
zulip_autoreload_start()
|
|
|
|
# start tornado web server in single-threaded mode
|
|
http_server = httpserver.HTTPServer(application,
|
|
xheaders=xheaders,
|
|
no_keep_alive=no_keep_alive)
|
|
http_server.listen(int(port), address=addr)
|
|
|
|
from zerver.tornado.ioloop_logging import logging_data
|
|
logging_data['port'] = port
|
|
setup_event_queue(int(port))
|
|
add_client_gc_hook(missedmessage_hook)
|
|
setup_tornado_rabbitmq()
|
|
|
|
instance = ioloop.IOLoop.instance()
|
|
|
|
if django.conf.settings.DEBUG:
|
|
instance.set_blocking_log_threshold(5)
|
|
instance.handle_callback_exception = handle_callback_exception
|
|
instance.start()
|
|
except KeyboardInterrupt:
|
|
sys.exit(0)
|
|
|
|
inner_run()
|