branch to handle unix sockets

This commit is contained in:
Benoit Chesneau 2010-02-03 13:35:32 +01:00
parent e804f97f5e
commit 0935ab3344
3 changed files with 68 additions and 43 deletions

View File

@ -140,7 +140,7 @@ class Arbiter(object):
self.log.error("should be a non GUNICORN environnement") self.log.error("should be a non GUNICORN environnement")
else: else:
raise raise
for i in range(5): for i in range(5):
try: try:
sock = self.init_socket(addr) sock = self.init_socket(addr)
@ -152,30 +152,46 @@ class Arbiter(object):
if i < 5: if i < 5:
self.log.error("Retrying in 1 second.") self.log.error("Retrying in 1 second.")
time.sleep(1) time.sleep(1)
if self.LISTENER: if self.LISTENER:
self.log.info("Listen on %s:%s" % self.LISTENER.getsockname()) try:
self.log.info("Listen on %s:%s" % self.LISTENER.getsockname())
except TypeError:
self.log.info("Listen on %s" % self.LISTENER.getsockname())
def init_socket_fromfd(self, fd, address): def init_socket_fromfd(self, fd, address):
sock = socket.fromfd(fd, socket.AF_INET, socket.SOCK_STREAM) if isinstance(address, basestring):
self.set_sockopts(sock) sock = socket.fromfd(fd, socket.AF_UNIX, socket.SOCK_STREAM)
else:
sock = socket.fromfd(fd, socket.AF_INET, socket.SOCK_STREAM)
self.set_tcp_sockopts(sock)
self.set_sockopts(sock, address)
return sock return sock
def init_socket(self, address): def init_socket(self, address):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) if isinstance(address, basestring):
self.set_sockopts(sock) try:
sock.bind(address) os.remove(address)
sock.listen(2048) except OSError:
pass
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
else:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.set_tcp_sockopts(sock)
self.set_sockopts(sock, address)
return sock return sock
def set_sockopts(self, sock): def set_tcp_sockopts(self, sock):
sock.setblocking(0)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
if hasattr(socket, "TCP_CORK"): if hasattr(socket, "TCP_CORK"):
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_CORK, 1) sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_CORK, 1)
elif hasattr(socket, "TCP_NOPUSH"): elif hasattr(socket, "TCP_NOPUSH"):
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NOPUSH, 1) sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NOPUSH, 1)
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
def set_sockopts(self, sock, address):
sock.setblocking(0)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(address)
sock.listen(2048)
def run(self): def run(self):
self.start() self.start()
self.manage_workers() self.manage_workers()

View File

@ -28,10 +28,8 @@ UMASK = 0
def options(): def options():
return [ return [
op.make_option('--host', dest='host', op.make_option('-b', '--bind', dest='bind',
help='Host to listen on. [%default]'), help='Adress to listen on. Ex. host:port or unix://path/to/socketfile'),
op.make_option('--port', dest='port', type='int',
help='Port to listen on. [%default]'),
op.make_option('--workers', dest='workers', type='int', op.make_option('--workers', dest='workers', type='int',
help='Number of workers to spawn. [%default]'), help='Number of workers to spawn. [%default]'),
op.make_option('-p','--pid', dest='pidfile', op.make_option('-p','--pid', dest='pidfile',
@ -95,21 +93,26 @@ def main(usage, get_app):
if opts.debug: if opts.debug:
workers = 1 workers = 1
host = opts.host or '127.0.0.1' bind = opts.bind or '127.0.0.1'
port = opts.port if bind.startswith("unix:"):
if port is None: addr = bind.split("unix:")[1]
if ':' in host: else:
host, port = host.split(':', 1) if ':' in bind:
host, port = bind.split(':', 1)
if not port.isdigit():
raise RuntimeError("%r is not a valid port number." % port)
port = int(port) port = int(port)
else: else:
host = bind
port = 8000 port = 8000
addr = (host, port)
kwargs = dict( kwargs = dict(
debug=opts.debug, debug=opts.debug,
pidfile=opts.pidfile pidfile=opts.pidfile
) )
arbiter = Arbiter((host,port), workers, app, arbiter = Arbiter(addr, workers, app,
**kwargs) **kwargs)
if opts.daemon: if opts.daemon:
daemonize() daemonize()
@ -229,8 +232,9 @@ def run_paster():
else: else:
workers = int(ctx.local_conf.get('workers', 1)) workers = int(ctx.local_conf.get('workers', 1))
opts.host = opts.host or ctx.local_conf.get('host', '127.0.0.1') host = opts.host or ctx.local_conf.get('host', '127.0.0.1')
opts.port = opts.port or int(ctx.local_conf.get('port', 8000)) port = opts.port or int(ctx.local_conf.get('port', 8000))
bind = "%s:%s" % (host, port)
debug = ctx.global_conf.get('debug') == "true" debug = ctx.global_conf.get('debug') == "true"
if debug: if debug:

View File

@ -30,7 +30,7 @@ class Command(BaseCommand):
help='Run daemonized in the background.'), help='Run daemonized in the background.'),
) )
help = "Starts a fully-functional Web server using gunicorn." help = "Starts a fully-functional Web server using gunicorn."
args = '[optional port number, or ipaddr:port]' args = '[optional port number, or ipaddr:port or unix:/path/to/sockfile]'
# Validation is called explicitly each time the server is reloaded. # Validation is called explicitly each time the server is reloaded.
requires_model_validation = False requires_model_validation = False
@ -38,20 +38,21 @@ class Command(BaseCommand):
def handle(self, addrport='', *args, **options): def handle(self, addrport='', *args, **options):
if args: if args:
raise CommandError('Usage is runserver %s' % self.args) raise CommandError('Usage is runserver %s' % self.args)
if not addrport:
addr = '' bind = addrport or '127.0.0.1'
port = '8000' if bind.startswith("unix:"):
addr = bind.split("unix:")[1]
else: else:
try: if ':' in bind:
addr, port = addrport.split(':') host, port = host.split(':', 1)
except ValueError: if not port.isdigit():
addr, port = '', addrport raise CommandError("%r is not a valid port number." % port)
if not addr: port = int(port)
addr = '127.0.0.1' else:
host = bind
if not port.isdigit(): port = 8000
raise CommandError("%r is not a valid port number." % port) addr = (host, port)
admin_media_path = options.get('admin_media_path', '') admin_media_path = options.get('admin_media_path', '')
workers = int(options.get('workers', '1')) workers = int(options.get('workers', '1'))
daemon = options.get('daemon') daemon = options.get('daemon')
@ -61,7 +62,11 @@ class Command(BaseCommand):
print "Validating models..." print "Validating models..."
self.validate(display_num_errors=True) self.validate(display_num_errors=True)
print "\nDjango version %s, using settings %r" % (django.get_version(), settings.SETTINGS_MODULE) print "\nDjango version %s, using settings %r" % (django.get_version(), settings.SETTINGS_MODULE)
print "Development server is running at http://%s:%s/" % (addr, port)
if isinstance(address, basestring):
print "Development server is running at unix:/" % addr
else:
print "Development server is running at http://%s:%s/" % addr
print "Quit the server with %s." % quit_command print "Quit the server with %s." % quit_command
# django.core.management.base forces the locale to en-us. # django.core.management.base forces the locale to en-us.
@ -69,7 +74,7 @@ class Command(BaseCommand):
try: try:
handler = AdminMediaHandler(WSGIHandler(), admin_media_path) handler = AdminMediaHandler(WSGIHandler(), admin_media_path)
arbiter = Arbiter((addr, int(port)), workers, handler, arbiter = Arbiter(addr, workers, handler,
pidfile=pidfile) pidfile=pidfile)
if daemon: if daemon:
daemonize() daemonize()