Skip to content

Instantly share code, notes, and snippets.

@cosven
Last active May 15, 2019 09:53
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cosven/49d2aa16d827f10afbb40d837329c8fd to your computer and use it in GitHub Desktop.
Save cosven/49d2aa16d827f10afbb40d837329c8fd to your computer and use it in GitHub Desktop.
reinvent the gunicorn
import os
import signal
import socket
import sys
import time
def be_a_worker(sock):
"""将当前进程变成一个 worker
worker 不处理请求之后,应该退出:也就是在退出 while 循环后,
调用 sys.exit(0) 来退出进程。
"""
stopped = False
pid = os.getpid()
print('Booting worker with pid: {}'.format(pid))
def stop(sig, frame):
nonlocal stopped
print(pid, 'recv term signal')
stopped = True
signal.signal(signal.SIGTERM, stop)
while not stopped:
# 多个 worker 等待 accpet 连接,当连接来了的时候,只有一个会成功
# 据说在低版本内核中,accept 会出现惊群,但现在不会了
conn, addr = sock.accept()
print('worker:{} recv request: {}'.format(pid, addr))
# 处理请求
# TODO: 这一块处理的逻辑,之后可以改进,比如遵守 WSGI 协议
# TODO: 以后,我们可以在这里给 conn 设置 close-on-exec
conn.recv(1024)
conn.sendall(b'HTTP/1.0 200 OK\r\n')
conn.close()
# worker 结束后,需要退出
sys.exit(0)
def run(worker_num=1, host='0.0.0.0', port=8081):
stopped = False
def stop(sig, frame):
nonlocal stopped
stopped = True
# 监听 Ctrl-c 信号
signal.signal(signal.SIGINT, stop)
worker_pids = []
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
sock.bind((host, port))
sock.listen(2048)
print('Medusa listening at {}:{}'.format(host, port))
for _ in range(0, worker_num):
pid = os.fork()
if pid != 0: # 主进程
worker_pids.append(pid)
continue
# 子进程
be_a_worker(sock)
# 主进程不用 sock 了,于是 close 它,这里其实不会真正的 shutdown 这个 socket
# 只会让 socket 的引用计数减 1(操作系统管理了这个引用计数,不是 Python 的引用计数)
sock.close()
# TODO: 在这里,可以作一些子进程管理的工作,比如检查子活着的子进程个数
# TODO: 还可以加个机制检测子进程的活跃程度
while not stopped:
time.sleep(0.1)
for pid in worker_pids:
os.kill(pid, signal.SIGTERM)
kpid, stat = os.waitpid(pid, os.WNOHANG)
if not kpid:
print('WARNING child process {} is still alive, force kill'.format(pid))
os.kill(pid, signal.SIGKILL)
if __name__ == '__main__':
run()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment