def tx_fn(pipeline: Pipeline) -> Response: """Code to be executed within a Redis transaction.""" rstates: List[Optional[bytes]] = pipeline.mget(rkeys) t_s: int t_us: int t_s, t_us = pipeline.time() t1 = t_s + t_us / 1000000 delay: float = 0 states: List[State] = [] for limit, rstate in zip(limits, rstates): t0, v0 = self._codec.decode(rstate) or (t1, 0) v1 = max(v0 - (t1 - t0) * limit.zone.rate, 0) + 1 c = limit.burst + 1 - v1 if c < -limit.delay: pipeline.unwatch() return Response(False, None) if c < 0: delay = max(delay, -c/limit.zone.rate) states.append(State(t1, v1)) pipeline.multi() for limit, rkey, state in zip(limits, rkeys, states): pipeline.setex(rkey, limit.zone.expiry, self._codec.encode(state)) return Response(True, delay)
def _set_client(self, client: Client, pipe: Pipeline) -> None: if ASSERTS: assert '!' not in client.name pipe.setex(f'#{client.id}', client.serialize(), self.default_address_ttl) pipe.setex(f'!{client.name}', client.id, self.default_address_ttl)
def _set_address(self, client: Client, ipv4_address: str, port: int, pipe: Pipeline) -> None: pipe.setex(f'{client.id}:{ipv4_address}', port, self.default_address_ttl)