def append_health_check_function(self, func_name, retry_period=5000): from inspect import signature if signature(func_name).return_annotation is not bool: raise TypeError(f"{func_name} must return a boolean") self._health_check_functions.append( {'func': func_name, 'retry_period': retry_period, 'last_check': datetime.now() - timedelta(days=1)}) if self.default_health_check_period > retry_period: self.health_check_period = retry_period logger.debug(f"New health check interval: {retry_period}")
def _publish(self, message, topic): properties = pika.BasicProperties( content_type='application/json', priority=0, delivery_mode=2, content_encoding="utf-8") logger.debug(f"Trying send message{message}") self._channel.basic_publish(exchange=topic, routing_key="", body=json.dumps(message, indent=4, sort_keys=True, default=str).encode(), properties=properties) logger.debug('message sent: %s', message)
def declare_topic(self, topic_name): try: if self._channel is None: self.connect() self._declare_topic(topic_name) except (pika.exceptions.ChannelWrongStateError, pika.exceptions.ConnectionClosed, pika.exceptions.ChannelClosed, pika.exceptions.ChannelClosedByBroker,pika.exceptions.ConnectionWrongStateError, pika.exceptions.StreamLostError): logger.debug('reconnecting to rabbit') self.connect() self._declare_topic(topic_name)
def send_message(self, message, topic): logger.debug(f"Insert data on TOPIC: {topic}") if not topic.startswith(self.config.get_event_name_prefix()): topic = f"{self.config.get_event_name_prefix()}{topic}" try: self._publish(message, topic) except (pika.exceptions.ChannelWrongStateError, pika.exceptions.ConnectionClosed, pika.exceptions.ChannelClosed, pika.exceptions.ChannelClosedByBroker, pika.exceptions.ConnectionWrongStateError, pika.exceptions.StreamLostError): logger.debug('reconnecting to queue') self.connect() self._publish(message, topic)
def process_next_message(self, queue_name, callback, model_validator, max_retry=0): sub_queue = self.get_simple_queue(queue_name) retry_count = 0 while True: try: msg = sub_queue.get(block=False, timeout=20) try: e = Event(**msg.payload) except ValueError as ve: logger.error( f"Rejecting not valid event payload: {msg.payload}") msg.ack() return True try: if model_validator is not None: try: call_result = callback( e, model_validator(**e.payload)) except Exception as error: logger.error( f"Invalid payload for type. Errors: {str(error)}" ) msg.ack() return True else: call_result = callback(e) if call_result: msg.ack() return True else: logger.debug("Callback returning false") msg.requeue() return False except: msg.requeue() return False except IOError: logger.error("Lost connection with Rabbit") self.queues = {} return False except Empty as e: if retry_count < max_retry: sleep(0.1) retry_count += 1 else: return True
def send_message(self, message, topic): # with self.send_connection as _conn: _conn = self.send_connection _conn.connect() # channel = _conn.channel() with _conn.channel() as channel: producer = Producer(channel) logger.debug(f"Insert data on TOPIC: {topic}") if not topic.startswith(self.config.get_event_name_prefix()): topic = f"{self.config.get_event_name_prefix()}{topic}" producer.publish(body=message, exchange=topic, routing_key=None) logger.debug(f"Message {message} sent to topic {topic}!")
def health_checks(self): previous_status = self.can_execute for check in self._health_check_functions: current_millis = datetime.now() if (current_millis - check['last_check']).total_seconds() * 1000 >= check['retry_period']: [x for x in self._health_check_functions if x['func'] == check['func']][0][ 'last_check'] = current_millis if not check['func'](): self.can_execute = 1 self.health_check_period = check["retry_period"] msg = f'Health check {check["func"].__name__} return False. Stop consuming for {check["retry_period"] / 1000} seconds.' if previous_status < 1: logger.info(msg) else: logger.debug(msg) return if self.can_execute > 0: self.can_execute = 0 self.health_check_period = self.default_health_check_period logger.info("Resuming consuming...")
def start_listening(self): try: logger.info("Starting consumer...") while True: current_millis = datetime.now() if (current_millis - self.last_health_check).total_seconds() * 1000 >= self.health_check_period: logger.debug("Health check time...") self.health_checks() self.last_health_check = datetime.now() try: if self.can_execute < 1: self.can_execute = self.check_events() if self.can_execute > 0: logger.error("Something happened on run... stop consuming") sleep(0.02) except Exception as err: self.can_execute = 2 self.health_check_period = self.health_check_period_on_critical_error logger.critical(str(err)) except KeyboardInterrupt: logger.debug('interrupted!')
def disconnect(self): if self._conn and self._conn.is_open: logger.debug('closing queue connection') self._conn.close()