Skip to content

Instantly share code, notes, and snippets.

@riffm
Created August 6, 2009 14:53
Show Gist options
  • Save riffm/163356 to your computer and use it in GitHub Desktop.
Save riffm/163356 to your computer and use it in GitHub Desktop.
# -*- coding: utf-8 -*-
import sys
import logging
import os
from os import path
logger = logging.getLogger(__name__)
def prepare_dir(filename):
dir = path.dirname(filename)
if not path.isdir(dir):
os.makedirs(dir)
def doublefork(pidfile, logfile, cur_dir):
try:
if os.fork() > 0:
sys.exit(0)
except OSError, e:
sys.exit('fork #1 failed: (%d) %s\n' % (e.errno, e.strerror))
os.setsid()
os.chdir(cur_dir)
os.umask(002)
# The second fork _is_ necessary. The first fork accomplishes
# two things - allow the shell to return, and allow you to do a setsid().
# The setsid() removes yourself from your controlling terminal.
# You see, before, you were still listed as a job of your previous process,
# and therefore the user might accidentally send you a signal.
# setsid() gives you a new session, and removes the existing controlling terminal.
# The problem is, you are now a session leader.
# As a session leader, if you open a file descriptor that is a terminal,
# it will become your controlling terminal (oops!).
# Therefore, the second fork makes you NOT be a session leader.
# Only session leaders can acquire a controlling terminal,
# so you can open up any file you wish without worrying
# that it will make you a controlling terminal.
# So - first fork - allow shell to return, and permit you to call setsid()
# Second fork - prevent you from accidentally reacquiring a controlling terminal.
try:
if os.fork() > 0:
sys.exit(0)
except OSError, e:
sys.exit('fork #2 failed: (%d) %s\n' % (e.errno, e.strerror))
si = open('/dev/null', 'r')
so = open(logfile, 'a+', 0)
# Even safer to flush first.
# Before dup'ing a new file into the underlying stdout/stderr file descriptors,
# you should flush the stdio buffers.
# Otherwise, it is entirely possible that pending output could get sent to the wrong file.
sys.stdout.flush()
sys.stderr.flush()
os.dup2(si.fileno(), sys.stdin.fileno())
os.dup2(so.fileno(), sys.stdout.fileno())
os.dup2(so.fileno(), sys.stderr.fileno())
sys.stdout = sys.stderr = so
fp = open(pidfile, 'w')
fp.write(str(os.getpid()))
fp.close()
def fastcgi(wsgi_app, cur_dir, bind='', pidfile='', logfile='', daemon=False):
"""Run fastcgi server at ./run/fcgi.sock"""
from flup.server import fcgi
run_dir = path.join(cur_dir, 'run')
pidfile = pidfile or path.join(run_dir, 'flup.pid')
prepare_dir(pidfile)
logfile = logfile or path.join(run_dir, 'flup.log')
prepare_dir(logfile)
if ':' in bind:
host, port = bind.split(':')
port = int(port)
else:
bind = bind or path.join(run_dir, 'fcgi.sock')
prepare_dir(bind)
if daemon:
if path.isfile(pidfile):
fp = open(pidfile, 'r')
pid = int(fp.read())
fp.close()
try:
os.kill(pid, 0)
print 'process allready running'
sys.exit(1)
except OSError, err:
logger.info('Process allready running: (%d) %s\n' % \
(err.errno, err.strerror))
doublefork(pidfile, logfile, cur_dir)
logger.info("Starting FastCGI server (flup), current dir '%s'" % cur_dir)
fcgi.WSGIServer(wsgi_app, bindAddress=bind, umask=002, debug=False).run()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment