def test_timeout_in_call(broker): timeout = 1 delay = timeout + 0.5 with Timer() as t: with pytest.raises(errors.Timeout) as exc: broker.execute("sleep", delay, timeout=timeout).result assert exc.value.args[0].endswith("/services/sleep") assert t.elapsed < delay assert t.elapsed > timeout
def __init__(self, http_session, service, args, kwargs, context): self.http_session = http_session self.timeout = check_timeout( kwargs.pop("timeout", self.default_timeout)) self.args = args self.kwargs = dict(kwargs) # local_only = self.kwargs.pop("local_only", False) # self.url = registry.instance().service_url(service, local_only=local_only) self.url = registry.instance().service_url(service) self.id = core.call_id() if context is None: context = ClientContext(self.id) self.context = context self.timer = Timer() self._response = None self._thread = t = threading.Thread(target=self._runner) t.setDaemon(True) t.start()
def from_dict(cls, d): ret = cls(d["task"]) ret._timers = {k: Timer.from_dict(v) for k, v in d["timers"].items()} ret._kids = [cls.from_dict(k) for k in d["kids"]] ret._notes = d["notes"] ret._host = d["host"] ret._pid = d["pid"] if "start" in d: ret._start = d["start"] if "stop" in d: ret._stop = d["stop"] return ret
def test_default_timeout_in_call(broker): default_timeout = client.get_default_timeout() client.Result._default_timeout = 1 delay = client.Result._default_timeout + 0.5 try: with Timer() as t: with pytest.raises(errors.Timeout) as exc: broker.execute("sleep", delay).result assert exc.value.args[0].endswith("/services/sleep") assert t.elapsed < delay assert t.elapsed > client.Result._default_timeout finally: client.Result._default_timeout = default_timeout
def test_execute_sync(broker): """Calls to ``servicelib.client.Broker.execute()`` are asynchronous Accessing the ``result`` or ``metadata`` fields of the returned value, however, are synchronous operations. """ delay = 1 with Timer() as t_complete: with Timer() as t_submit: res = broker.execute("sleep", delay) assert res.result assert t_submit.elapsed < delay assert t_complete.elapsed > delay with Timer() as t_complete: with Timer() as t_submit: res = broker.execute("sleep", delay) assert res.metadata assert t_submit.elapsed < delay assert t_complete.elapsed > delay
def from_http_headers(cls, h): ret = cls(h["task"]) ret._timers = { k: Timer.from_dict(v) for k, v in json.loads(h["timers"]).items() } ret._kids = [cls.from_dict(k) for k in json.loads(h["kids"])] ret._host = h["host"] ret._pid = int(h["pid"]) ret._start = float(h["start"]) ret._stop = float(h["stop"]) ret._notes = { k[len("note-"):]: json.loads(v) for (k, v) in h.items() if k.startswith("note-") } return ret
def test_timeout_in_wait(broker): timeout = 1 delay = timeout + 0.5 res = broker.execute("sleep", delay) # The first call to `wait()` times out. with Timer() as t: with pytest.raises(errors.Timeout) as exc: res.wait(timeout) assert exc.value.args[0].endswith("/services/sleep") assert t.elapsed < delay assert t.elapsed > timeout # Ensure enough time passes for the server side to complete its # call. time.sleep(delay) # The second one succeeds. res.wait(timeout)
def test_parallel_requests(broker): """All instances of services handle requests concurrently. """ w = broker.worker_info num_calls = (w["num_processes"] * w["num_threads"]) + 1 delay = 2 overhead = 1 def sleep(): broker.execute("sleep", delay).wait() calls = [] with Timer() as t: for _ in range(num_calls): c = threading.Thread(target=sleep) c.start() calls.append(c) for c in calls: c.join() assert t.elapsed >= 2 * delay assert t.elapsed < 2 * delay + overhead
class Result(object): log = logutils.get_logger(__name__) _default_timeout = None def __init__(self, http_session, service, args, kwargs, context): self.http_session = http_session self.timeout = check_timeout( kwargs.pop("timeout", self.default_timeout)) self.args = args self.kwargs = dict(kwargs) # local_only = self.kwargs.pop("local_only", False) # self.url = registry.instance().service_url(service, local_only=local_only) self.url = registry.instance().service_url(service) self.id = core.call_id() if context is None: context = ClientContext(self.id) self.context = context self.timer = Timer() self._response = None self._thread = t = threading.Thread(target=self._runner) t.setDaemon(True) t.start() def _runner(self): self.timer.start() try: req = core.Request(*self.args, **self.kwargs) self.log.debug( "POST %s, headers: %s, body: %s", self.url, req.http_headers, req.http_body, ) # XXX It's not entirely clear that `requests.Session` is thread-safe. res = self.http_session.post( self.url, data=req.http_body, headers=req.http_headers, timeout=self.timeout, ) res = core.Response.from_http(res.status_code, res.content, res.headers) self.log.debug("Response: %r", res) self.timer.stop() self.context.update_metadata(res.metadata) except requests.Timeout as exc: self.log.debug("Got timeout error: %s", exc) res = errors.Timeout(self.url) except Exception as exc: self.log.info( "%r failed: %s", self, exc, exc_info=True, stack_info=True, ) res = exc res.metadata = self.context.metadata self._response = res def wait(self, timeout=None): if self._response is None: self._thread.join(timeout=timeout) if timeout is not None: if self._thread.is_alive(): raise errors.Timeout(self.url) if isinstance(self._response, Exception): raise self._response result = self._response.value if isinstance(result, Exception): raise result return result, self._response.metadata @property def result(self): r, _ = self.wait() return r @property def metadata(self): _, m = self.wait() return m def __repr__(self): return "Result(%r, %r)" % ( self.url, self.args, ) @property def default_timeout(self): if self.__class__._default_timeout is None: self.__class__._default_timeout = get_default_timeout() return self.__class__._default_timeout
def timer(self, name): if name not in self._timers: self._timers[name] = Timer() return self._timers[name]