def handle(self, *args, **options): if options['blacklist']: self.resolve_blacklist() return while True: try: # poll by the second if not settings.LOCAL: time.sleep(1) # TODO - All should be a transaction atomic function response = sqs_client.receive_message( QueueUrl=settings.QUEUE_URL, AttributeNames=['MessageDeduplicationId'], MessageAttributeNames=['All'], MaxNumberOfMessages=1, ) messages = response.get('Messages') if not messages: continue # There is only ever 1 because MaxNumberOfMessages=1 message = Message.from_event(messages[0]) already_deduplicated = redis_client.get(message.message_deduplication_id) if already_deduplicated and already_deduplicated.decode('UTF-8') == 'True': self.remove_from_queue(message) continue # If someone uploads a data hash that is faulty, then we want to blacklist all events around that # bounty id. It can either be a permanent blacklist, typically added manually, or a pending blacklist. # All the events in the pending blacklist will retry later. permanent_blacklist = redis_client.get('blacklist:{}'.format(message.bounty_id)) pending_blacklist = redis_client.exists('pending_blacklist:{}'.format(message.bounty_id)) if permanent_blacklist or pending_blacklist: self.remove_from_queue(message) if permanent_blacklist: logger.info('Skipping event for {}, permanent blacklist found'.format(message.bounty_id)) else: logger.info('Pending blacklist exists for {}, adding event {}'.format(message.bounty_id, message.event)) self.add_to_blacklist(message) continue self.handle_message(message) self.remove_from_queue(message) except Exception as e: # goes to rollbar logger.error(e) self.remove_from_queue(message) self.add_to_blacklist(message)
def handle(self, *args, **options): try: while True: # poll by the second if not settings.LOCAL: time.sleep(1) # TODO - All should be a transaction atomic function response = sqs_client.receive_message( QueueUrl=settings.QUEUE_URL, AttributeNames=['MessageDeduplicationId'], MessageAttributeNames=['All'], ) messages = response.get('Messages') if not messages: continue message = messages[0] receipt_handle = message['ReceiptHandle'] message_attributes = message['MessageAttributes'] event = message_attributes['Event']['StringValue'] bounty_id = int(message_attributes['BountyId']['StringValue']) fulfillment_id = int( message_attributes['FulfillmentId']['StringValue']) message_deduplication_id = message_attributes[ 'MessageDeduplicationId']['StringValue'] transaction_from = message_attributes['TransactionFrom'][ 'StringValue'] transaction_hash = message_attributes['TransactionHash'][ 'StringValue'] event_timestamp = message_attributes['TimeStamp'][ 'StringValue'] contract_method_inputs = json.loads( message_attributes['ContractMethodInputs']['StringValue']) event_date = datetime.datetime.fromtimestamp( int(event_timestamp)) # If someone uploads a data hash that is faulty, then we want to blacklist all events around that # bounty id. We manage this manually if redis_client.get('blacklist:' + str(bounty_id)): redis_client.set(message_deduplication_id, True) sqs_client.delete_message( QueueUrl=settings.QUEUE_URL, ReceiptHandle=receipt_handle, ) continue logger.info('attempting {}: for bounty id {}'.format( event, str(bounty_id))) if event == 'BountyIssued': master_client.bounty_issued( bounty_id, event_date=event_date, inputs=contract_method_inputs, event_timestamp=event_timestamp) if event == 'BountyActivated': master_client.bounty_activated( bounty_id, event_date=event_date, inputs=contract_method_inputs, event_timestamp=event_timestamp) if event == 'BountyFulfilled': master_client.bounty_fulfilled( bounty_id, fulfillment_id=fulfillment_id, event_date=event_date, inputs=contract_method_inputs, event_timestamp=event_timestamp, transaction_issuer=transaction_from) if event == 'FulfillmentUpdated': master_client.fullfillment_updated( bounty_id, event_date=event_date, fulfillment_id=fulfillment_id, inputs=contract_method_inputs) if event == 'FulfillmentAccepted': master_client.fulfillment_accepted( bounty_id, event_date=event_date, fulfillment_id=fulfillment_id, event_timestamp=event_timestamp) if event == 'BountyKilled': master_client.bounty_killed( bounty_id, event_date=event_date, event_timestamp=event_timestamp) if event == 'ContributionAdded': master_client.contribution_added( bounty_id, event_date=event_date, inputs=contract_method_inputs, event_timestamp=event_timestamp) if event == 'DeadlineExtended': master_client.deadline_extended( bounty_id, event_date=event_date, inputs=contract_method_inputs, event_timestamp=event_timestamp) if event == 'BountyChanged': master_client.bounty_changed(bounty_id, event_date=event_date, inputs=contract_method_inputs) if event == 'IssuerTransferred': master_client.issuer_transferred( bounty_id, transaction_from=transaction_from, event_date=event_date, inputs=contract_method_inputs) if event == 'PayoutIncreased': master_client.payout_increased( bounty_id, event_date=event_date, inputs=contract_method_inputs) logger.info(event) # This means the contract subscriber will never send this event # through to sqs again Event.objects.get_or_create( event=event, transaction_hash=transaction_hash, defaults={ 'bounty_id': bounty_id, 'fulfillment_id': fulfillment_id if fulfillment_id != -1 else None, 'transaction_from': transaction_from, 'contract_inputs': contract_method_inputs, 'event_date': event_date, }) redis_client.set(message_deduplication_id, True) sqs_client.delete_message( QueueUrl=settings.QUEUE_URL, ReceiptHandle=receipt_handle, ) except Exception as e: # goes to rollbar logger.exception(e) raise e
def handle(self, *args, **options): try: bounty_client = BountyClient() sc = SlackClient(settings.SLACK_TOKEN) while True: # poll by the second if not settings.LOCAL: time.sleep(1) response = sqs_client.receive_message( QueueUrl=settings.QUEUE_URL, AttributeNames=['MessageDeduplicationId'], MessageAttributeNames=['All'], ) messages = response.get('Messages') if not messages: continue message = messages[0] receipt_handle = message['ReceiptHandle'] message_attributes = message['MessageAttributes'] event = message_attributes['Event']['StringValue'] bounty_id = int(message_attributes['BountyId']['StringValue']) fulfillment_id = int( message_attributes['FulfillmentId']['StringValue']) message_deduplication_id = message_attributes[ 'MessageDeduplicationId']['StringValue'] transaction_from = message_attributes['TransactionFrom'][ 'StringValue'] event_timestamp = message_attributes['TimeStamp'][ 'StringValue'] contract_method_inputs = json.loads( message_attributes['ContractMethodInputs']['StringValue']) # If someone uploads a data hash that is faulty, then we want to blacklist all events around that # bounty id. We manage this manually if redis_client.get('blacklist:' + str(bounty_id)): redis_client.set(message_deduplication_id, True) sqs_client.delete_message( QueueUrl=settings.QUEUE_URL, ReceiptHandle=receipt_handle, ) continue logger.info('attempting {}: for bounty id {}'.format( event, str(bounty_id))) if event == 'BountyIssued': bounty_client.issue_bounty(bounty_id, contract_method_inputs, event_timestamp) if event == 'BountyActivated': bounty_client.activate_bounty(bounty_id, contract_method_inputs) if event == 'BountyFulfilled': bounty_client.fulfill_bounty(bounty_id, fulfillment_id, contract_method_inputs, event_timestamp, transaction_from) if event == 'FulfillmentUpdated': bounty_client.update_fulfillment(bounty_id, fulfillment_id, contract_method_inputs) if event == 'FulfillmentAccepted': bounty_client.accept_fulfillment(bounty_id, fulfillment_id) if event == 'BountyKilled': bounty_client.kill_bounty(bounty_id) if event == 'ContributionAdded': bounty_client.add_contribution(bounty_id, contract_method_inputs) if event == 'DeadlineExtended': bounty_client.extend_deadline(bounty_id, contract_method_inputs) if event == 'BountyChanged': bounty_client.change_bounty(bounty_id, contract_method_inputs) if event == 'IssuerTransferred': bounty_client.transfer_issuer(bounty_id, contract_method_inputs) if event == 'PayoutIncreased': bounty_client.increase_payout(bounty_id, contract_method_inputs) logger.info(event) # We should create a separate client to manage these # notifications to slack sc.api_call('chat.postMessage', channel=settings.NOTIFICATIONS_SLACK_CHANNEL, text='Event {} passed for bounty {}'.format( event, str(bounty_id))) # This means the contract subscriber will never send this event # through to sqs again redis_client.set(message_deduplication_id, True) sqs_client.delete_message( QueueUrl=settings.QUEUE_URL, ReceiptHandle=receipt_handle, ) except Exception as e: # goes to rollbar logger.exception(e) raise e