Skip to content

Instantly share code, notes, and snippets.

@matthewstory
Last active January 20, 2022 15:05
Show Gist options
  • Save matthewstory/4547282 to your computer and use it in GitHub Desktop.
Save matthewstory/4547282 to your computer and use it in GitHub Desktop.

Revisions

  1. matthewstory revised this gist Mar 31, 2014. 1 changed file with 19 additions and 4 deletions.
    23 changes: 19 additions & 4 deletions gistfile1.py
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,7 @@
    import os
    import signal
    import sys
    import select
    import errno

    from jsonrpclib.SimpleJSONRPCServer import SimpleJSONRPCServer
    @@ -29,7 +30,7 @@ def _gogentle(signum, frame):
    '''Do not throw a KeyboardInterrupt Error'''
    os._exit(1)

    # API
    # API
    def add(x, y):
    '''Add x and y'''
    return x + y
    @@ -55,7 +56,7 @@ def main(name, *argv):
    # fork our current process
    pid = os.fork()

    # if we are the child fork ...
    # if we are the child fork ...
    if 0 == pid:
    # die without unhandled exception
    for signum in ( signal.SIGINT, signal.SIGTERM, ):
    @@ -75,8 +76,22 @@ def main(name, *argv):

    # wait on the kids
    while len(_PIDS):
    pid, rc = os.waitpid(-1, 0)
    _PIDS.remove(pid)
    # 1s timeout here means we're checking for exiting children at most
    # 1x per second, prevents a busy loop
    reads, _, _ = select.select([sys.stdin], [], [], 1)
    if sys.stdin in reads:
    # blocking, read 1 line
    cmd = sys.stdin.readline()
    # kill ourselves ... kronos will propegate
    if cmd.strip() == 'exit':
    os.kill(os.getpid(), signal.SIGTERM)

    # check for exited children, non-blocking
    while True:
    pid, rc = os.waitpid(-1, os.WNOHANG)
    if not pid:
    break
    _PIDS.remove(pid)

    return 0

  2. matthewstory created this gist Jan 16, 2013.
    84 changes: 84 additions & 0 deletions gistfile1.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,84 @@
    import os
    import signal
    import sys
    import errno

    from jsonrpclib.SimpleJSONRPCServer import SimpleJSONRPCServer

    # BOOK-KEEPING
    _PIDS = []

    def _kronos(signum, frame):
    '''As Kronos did before us, we too may have to devour our children'''
    for pid in _PIDS:
    try:
    os.kill(pid, signum)
    except OSError, e:
    if e.errno == errno.ESRCH:
    _PIDS.remove(pid)

    # wait on all child processes
    while len(_PIDS):
    pid, rc = os.waitpid(-1, 0)
    _PIDS.remove(pid)

    # exit non-zero to signal abnormal termination
    sys.exit(1)

    def _gogentle(signum, frame):
    '''Do not throw a KeyboardInterrupt Error'''
    os._exit(1)

    # API
    def add(x, y):
    '''Add x and y'''
    return x + y

    def subtract(x, y):
    '''Subtract y from x'''
    return x - y

    # server
    def main(name, *argv):
    global _PIDS

    # JSON-RPC over HTTP on INET socket localhost:8888
    # under the hood, this calls `socket.bind` then `socket.listen`
    s = SimpleJSONRPCServer(( argv[0], int(argv[1]), ))

    # register our logging math functions
    for fn in ( add, subtract, ):
    s.register_function(fn)

    # simple pre-fork server, fork before accept
    for i in range(int(argv[2])):
    # fork our current process
    pid = os.fork()

    # if we are the child fork ...
    if 0 == pid:
    # die without unhandled exception
    for signum in ( signal.SIGINT, signal.SIGTERM, ):
    signal.signal(signum, _gogentle)

    # under the hood, this calls `socket.accept`
    s.serve_forever()
    os._exit(0)

    # if we are the papa fork
    else:
    _PIDS.append(pid)

    # setup signal relaying for INT and TERM
    for signum in ( signal.SIGINT, signal.SIGTERM, ):
    signal.signal(signum, _kronos)

    # wait on the kids
    while len(_PIDS):
    pid, rc = os.waitpid(-1, 0)
    _PIDS.remove(pid)

    return 0

    if __name__ == '__main__':
    sys.exit(main(*sys.argv))