X-Git-Url: http://www.dolda2000.com/gitweb/?a=blobdiff_plain;f=python3%2Fashd%2Fserve.py;h=ecc8d46697baa404dad46cd284288b1fb963f2af;hb=dd1e6b987332cd05bb0cf70109b140ce24c5502a;hp=d78cec9f7a50d0d761f035fe77b92789b98f2d69;hpb=d570c3a5c601a7484761f547e8c655eefca70230;p=ashd.git diff --git a/python3/ashd/serve.py b/python3/ashd/serve.py index d78cec9..ecc8d46 100644 --- a/python3/ashd/serve.py +++ b/python3/ashd/serve.py @@ -75,29 +75,79 @@ class handler(object): def handle(self, request): raise Exception() def ckflush(self, req): - raise Exception() + while len(req.buffer) > 0: + rls, wls, els = select.select([], [req], [req]) + req.flush() def close(self): pass + @classmethod + def parseargs(cls, **args): + if len(args) > 0: + raise ValueError("unknown handler argument: " + next(iter(args))) + return {} + +class single(handler): + def handle(self, req): + try: + env = req.mkenv() + with perf.request(env) as reqevent: + respiter = req.handlewsgi(env, req.startreq) + for data in respiter: + req.write(data) + if req.status: + reqevent.response([req.status, req.headers]) + req.flushreq() + self.ckflush(req) + except closed: + pass + except: + log.error("exception occurred when handling request", exc_info=True) + finally: + req.close() + class freethread(handler): - def __init__(self, **kw): + def __init__(self, *, max=None, timeout=None, **kw): super().__init__(**kw) self.current = set() self.lk = threading.Lock() + self.tcond = threading.Condition(self.lk) + self.max = max + self.timeout = timeout - def handle(self, req): - reqthread(target=self.run, args=[req]).start() + @classmethod + def parseargs(cls, *, max=None, abort=None, **args): + ret = super().parseargs(**args) + if max: + ret["max"] = int(max) + if abort: + ret["timeout"] = int(abort) + return ret - def ckflush(self, req): - while len(req.buffer) > 0: - rls, wls, els = select.select([], [req], [req]) - req.flush() + def handle(self, req): + with self.lk: + if self.max is not None: + if self.timeout is not None: + now = start = time.time() + while len(self.current) >= self.max: + self.tcond.wait(start + self.timeout - now) + now = time.time() + if now - start > self.timeout: + os.abort() + else: + while len(self.current) >= self.max: + self.tcond.wait() + th = reqthread(target=self.run, args=[req]) + th.start() + while th.is_alive() and th not in self.current: + self.tcond.wait() def run(self, req): try: th = threading.current_thread() with self.lk: self.current.add(th) + self.tcond.notify_all() try: env = req.mkenv() with perf.request(env) as reqevent: @@ -115,6 +165,7 @@ class freethread(handler): finally: with self.lk: self.current.remove(th) + self.tcond.notify_all() finally: req.close() @@ -124,11 +175,11 @@ class freethread(handler): if len(self.current) > 0: th = next(iter(self.current)) else: - th = None + return th.join() class threadpool(handler): - def __init__(self, *, min=0, max=20, live=10, **kw): + def __init__(self, *, min=0, max=20, live=300, **kw): super().__init__(**kw) self.current = set() self.free = set() @@ -142,6 +193,17 @@ class threadpool(handler): for i in range(self.min): self.newthread() + @classmethod + def parseargs(cls, *, min=None, max=None, live=None, **args): + ret = super().parseargs(**args) + if min: + ret["min"] = int(min) + if max: + ret["max"] = int(max) + if live: + ret["live"] = int(live) + return ret + def newthread(self): with self.lk: th = reqthread(target=self.loop) @@ -149,11 +211,6 @@ class threadpool(handler): while not th in self.current: self.pcond.wait() - def ckflush(self, req): - while len(req.buffer) > 0: - rls, wls, els = select.select([], [req], [req]) - req.flush() - def _handle(self, req): try: env = req.mkenv() @@ -226,5 +283,23 @@ class threadpool(handler): self.rcond.notify_all() self.pcond.wait(1) -names = {"free": freethread, +names = {"single": single, + "free": freethread, "pool": threadpool} + +def parsehspec(spec): + if ":" not in spec: + return spec, {} + nm, spec = spec.split(":", 1) + args = {} + while spec: + if "," in spec: + part, spec = spec.split(",", 1) + else: + part, spec = spec, None + if "=" in part: + key, val = part.split("=", 1) + else: + key, val = part, "" + args[key] = val + return nm, args