def test_pop_pending_limit(self): k = pending_key('test') for t in range(5, 40, 5): yield add_pending(self.redis, 'test', { 'owner_id': '1234', 'timestamp': t, 'attempts': 0, 'intervals': [10], 'request': {'foo': t} }) pending = yield zitems(self.redis, k) pending_reqs = [r for t, r in pending] result = yield pop_pending(self.redis, 'test', 0, 50, limit=2) self.assertEqual(result, pending_reqs[:2]) self.assertEqual((yield zitems(self.redis, k)), pending[2:]) result = yield pop_pending(self.redis, 'test', 0, 50, limit=3) self.assertEqual(result, pending_reqs[2:5]) self.assertEqual((yield zitems(self.redis, k)), pending[5:]) result = yield pop_pending(self.redis, 'test', 0, 50, limit=3) self.assertEqual(result, pending_reqs[5:]) self.assertEqual((yield zitems(self.redis, k)), []) result = yield pop_pending(self.redis, 'test', 0, 50, limit=3) self.assertEqual(result, []) self.assertEqual((yield zitems(self.redis, k)), [])
def route_requests(self, req, body): owner_id = req.getHeader('x-owner-id') req_limit = self.config.request_limit if (yield self.req_limit_reached(owner_id)): self.log( "Request limit reached for %s at a request count of %d" % (owner_id, req_limit)) returnValue(response(req, { 'errors': [{ 'type': 'too_many_requests', 'message': ( "Only %d unfinished requests are allowed per owner" % (req_limit)) }] }, code=429)) else: data = { 'owner_id': req.getHeader('x-owner-id'), 'timestamp': time.time(), 'request': body['request'], 'intervals': body['intervals'] } self.log("Adding request to pending set", data) yield add_pending(self.redis, self.prefix, data) yield inc_req_count(self.redis, self.prefix, owner_id) returnValue(response(req, {}))
def test_add_pending_next_retry(self): k = pending_key('test') self.assertEqual((yield zitems(self.redis, k)), []) yield add_pending(self.redis, 'test', { 'owner_id': '1234', 'timestamp': 10, 'attempts': 1, 'intervals': [50, 60], 'request': {'foo': 23} }) self.assertEqual((yield zitems(self.redis, k)), [ (10 + 60, { 'owner_id': '1234', 'timestamp': 10, 'attempts': 1, 'intervals': [50, 60], 'request': {'foo': 23}, }), ]) yield add_pending(self.redis, 'test', { 'owner_id': '1234', 'timestamp': 5, 'attempts': 2, 'intervals': [20, 90, 100], 'request': {'bar': 42} }) self.assertEqual((yield zitems(self.redis, k)), [ (10 + 60, { 'owner_id': '1234', 'timestamp': 10, 'attempts': 1, 'intervals': [50, 60], 'request': {'foo': 23}, }), (5 + 100, { 'owner_id': '1234', 'timestamp': 5, 'attempts': 2, 'intervals': [20, 90, 100], 'request': {'bar': 42}, }), ])
def test_maintain(self): k_p = pending_key('test') k_r = ready_key('test') worker = yield self.mk_worker({ 'redis_prefix': 'test', 'frequency': 20, }) worker.stop() for t in range(5, 25, 5): yield add_pending(worker.redis, 'test', { 'owner_id': '1234', 'timestamp': t, 'attempts': 0, 'intervals': [10], 'request': {'foo': t} }) pending = yield zitems(worker.redis, pending_key('test')) pending_reqs = [v for t, v in pending] worker.clock.advance(10) self.assertEqual((yield lvalues(worker.redis, k_r)), []) self.assertEqual((yield zitems(worker.redis, k_p)), pending) yield worker.maintain() self.assertEqual((yield lvalues(worker.redis, k_r)), []) self.assertEqual((yield zitems(worker.redis, k_p)), pending) worker.clock.advance(5) self.assertEqual((yield lvalues(worker.redis, k_r)), []) self.assertEqual((yield zitems(worker.redis, k_p)), pending) yield worker.maintain() self.assertEqual((yield lvalues(worker.redis, k_r)), pending_reqs[:1]) self.assertEqual((yield zitems(worker.redis, k_p)), pending[1:]) worker.clock.advance(10) self.assertEqual((yield lvalues(worker.redis, k_r)), pending_reqs[:1]) self.assertEqual((yield zitems(worker.redis, k_p)), pending[1:]) yield worker.maintain() self.assertEqual((yield lvalues(worker.redis, k_r)), pending_reqs[:3]) self.assertEqual((yield zitems(worker.redis, k_p)), pending[3:]) worker.clock.advance(5) self.assertEqual((yield lvalues(worker.redis, k_r)), pending_reqs[:3]) self.assertEqual((yield zitems(worker.redis, k_p)), pending[3:]) yield worker.maintain() self.assertEqual((yield lvalues(worker.redis, k_r)), pending_reqs) self.assertEqual((yield zitems(worker.redis, k_p)), [])
def test_pop_pending_add_ready(self): k_p = pending_key('test') k_r = ready_key('test') for t in range(5, 40, 5): yield add_pending(self.redis, 'test', { 'owner_id': '1234', 'timestamp': t, 'attempts': 0, 'intervals': [10], 'request': {'foo': t} }) pending_reqs = [r for t, r in (yield zitems(self.redis, k_p))] yield pop_pending_add_ready(self.redis, 'test', 0, 50) self.assertEqual((yield lvalues(self.redis, k_r)), pending_reqs) self.assertEqual((yield zitems(self.redis, k_p)), [])
def test_pop_pending_no_deserialize(self): k = pending_key('test') for t in range(5, 35, 5): yield add_pending(self.redis, 'test', { 'owner_id': '1234', 'timestamp': t, 'attempts': 0, 'intervals': [10], 'request': {'foo': t} }) pending = yield zitems(self.redis, k) pending_reqs = [r for t, r in pending] result = yield pop_pending( self.redis, 'test', 0, 10 + 13, deserialize=False) self.assertEqual([json.loads(r) for r in result], pending_reqs[:2])
def test_pop_pending_add_ready_chunks_tap(self): k_p = pending_key('test') taps = [] for t in range(5, 40, 5): yield add_pending(self.redis, 'test', { 'owner_id': '1234', 'timestamp': t, 'attempts': 0, 'intervals': [10], 'request': {'foo': t} }) pending_reqs = yield self.redis.zrange(k_p, 0, -1) yield pop_pending_add_ready( self.redis, 'test', 0, 50, chunk_size=3, tap=taps.append) self.assertEqual(taps, [ pending_reqs[:3], pending_reqs[3:6], pending_reqs[6:], ])
def test_pop_pending_add_ready_chunks(self): calls = self.redis_spy('zrangebyscore') k = pending_key('test') for t in range(5, 40, 5): yield add_pending(self.redis, 'test', { 'owner_id': '1234', 'timestamp': t, 'attempts': 0, 'intervals': [10], 'request': {'foo': t} }) yield pop_pending_add_ready( self.redis, 'test', 0, 50, chunk_size=3) self.assertEqual(calls, 4 * [ ((k, 0, 50), { 'offset': 0, 'count': 3 }), ])
def test_loop(self): k_p = pending_key('test') k_r = ready_key('test') msgs = self.patch_log() worker = yield self.mk_worker({ 'redis_prefix': 'test', 'frequency': 5, }) for t in range(5, 25, 5): yield add_pending(worker.redis, 'test', { 'owner_id': '1234', 'timestamp': t, 'attempts': 0, 'intervals': [10], 'request': {'foo': t} }) pending = yield zitems(worker.redis, pending_key('test')) pending_reqs = [v for t, v in pending] self.assertEqual(pop_all(msgs), [ 'Checking for requests to move from pending to ready', ]) worker.maintains.pop() worker.clock.advance(5) yield worker.maintains.pop() self.assertEqual((yield lvalues(worker.redis, k_r)), []) self.assertEqual((yield zitems(worker.redis, k_p)), pending) self.assertEqual(pop_all(msgs), [ 'Checking for requests to move from pending to ready', ]) worker.clock.advance(5) yield worker.maintains.pop() self.assertEqual((yield lvalues(worker.redis, k_r)), []) self.assertEqual((yield zitems(worker.redis, k_p)), pending) self.assertEqual(pop_all(msgs), [ 'Checking for requests to move from pending to ready', ]) worker.clock.advance(5) yield worker.maintains.pop() self.assertEqual((yield lvalues(worker.redis, k_r)), pending_reqs[:1]) self.assertEqual((yield zitems(worker.redis, k_p)), pending[1:]) self.assertEqual(pop_all(msgs), [ 'Checking for requests to move from pending to ready', '1 request(s) moved from pending to ready', ]) worker.clock.advance(5) yield worker.maintains.pop() self.assertEqual((yield lvalues(worker.redis, k_r)), pending_reqs[:2]) self.assertEqual((yield zitems(worker.redis, k_p)), pending[2:]) self.assertEqual(pop_all(msgs), [ 'Checking for requests to move from pending to ready', '1 request(s) moved from pending to ready', ]) worker.clock.advance(5) yield worker.maintains.pop() self.assertEqual((yield lvalues(worker.redis, k_r)), pending_reqs[:3]) self.assertEqual((yield zitems(worker.redis, k_p)), pending[3:]) self.assertEqual(pop_all(msgs), [ 'Checking for requests to move from pending to ready', '1 request(s) moved from pending to ready', ]) worker.clock.advance(5) yield worker.maintains.pop() self.assertEqual((yield lvalues(worker.redis, k_r)), pending_reqs) self.assertEqual((yield zitems(worker.redis, k_p)), []) self.assertEqual(pop_all(msgs), [ 'Checking for requests to move from pending to ready', '1 request(s) moved from pending to ready', ]) self.assertEqual(worker.maintains, []) worker.stop() worker.clock.advance(5) self.assertEqual(worker.maintains, []) self.assertEqual(pop_all(msgs), [])