def __deliver_response(rid): """ The delivery task for a given request id :param rid: Request id """ def deliver_message(): reply(message, headers=headers, **response.sink.recipient) return len(str(message)) response = None try: response = build_response(rid) delivery_state = response.sink.delivery if delivery_state == 'ready': messages = response.build() # The creation of a response object may change the corresponding request delivery state # (mixing, streaming, etc). The thing is that it was 'ready' before, # so it should has something prepared to deliver. n_messages = 0 deliver_weight = 0 message, headers = messages.next() # Actually, this is the trigger deliver_weight += deliver_message() n_messages += 1 deliver_delta = 0 for (message, headers) in messages: message_weight = deliver_message() deliver_weight += message_weight deliver_delta += message_weight n_messages += 1 if deliver_delta > 1000: deliver_delta = 0 __log.info('Delivering response of request {} [{} kB]'.format(rid, deliver_weight / 1000.0)) deliver_weight /= 1000.0 __log.info('{} messages delivered for request {} [{} kB]'.format(n_messages, rid, deliver_weight)) elif delivery_state == 'accepted': __log.error('Request {} should not be marked as deliver-ready, its state is inconsistent'.format(rid)) else: __log.info('Response of request {} is being delivered by other means...'.format(rid)) r.srem(__ready_key, rid) except StopIteration: # There was nothing prepared to deliver (Its state may have changed to # 'streaming') r.srem(__ready_key, rid) except (EnvironmentError, AttributeError, Exception), e: r.srem(__ready_key, rid) # traceback.print_exc() __log.warning(e.message) if response is not None: __log.error('Force remove of request {} due to a delivery error'.format(rid)) response.sink.remove() else: __log.error("Couldn't remove request {}".format(rid))
def __deliver_responses(): import time __log.info('Delivery daemon started') # Declare in-progress deliveries dictionary futures = {} while True: try: # Get all ready deliveries ready = r.smembers(__ready_key) for rid in ready: # If the delivery is not in the thread pool, just submit it if rid not in futures: __log.info('Response delivery of request {} is ready. Putting it in queue...'.format(rid)) futures[rid] = __thp.submit(__deliver_response, rid) # Clear futures that have already ceased to be ready for obsolete_rid in set.difference(set(futures.keys()), ready): if obsolete_rid in futures and futures[obsolete_rid].done(): del futures[obsolete_rid] # All those deliveries that are marked as 'sent' are being cleared here along its request data sent = r.smembers(__sent_key) for rid in sent: r.srem(__ready_key, rid) r.srem(__deliveries_key, rid) try: response = build_response(rid) response.sink.remove() # Its lock is removed too __log.info('Request {} was sent and cleared'.format(rid)) except AttributeError: traceback.print_exc() __log.warning('Request number {} was deleted by other means'.format(rid)) pass r.srem(__sent_key, rid) except Exception as e: __log.error(e.message) traceback.print_exc() finally: time.sleep(0.1)