Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

172 lines
7.0KB

  1. from confluent_kafka import Producer, Consumer, KafkaException, KafkaError
  2. import os,time
  3. from config import conf
  4. # 定义全局 redis_helper
  5. kafka_client = None
  6. class KafkaClient:
  7. def __init__(self):
  8. bootstrap_servers=conf().get("kafka_bootstrap_servers")
  9. agent_tel=os.environ.get('tel', '18029274615')
  10. consumer_group=f'aiops-wx_{agent_tel}'
  11. print(f'kafka消费组 {consumer_group}')
  12. topic="topic.ai.ops.wx"
  13. self.bootstrap_servers = bootstrap_servers
  14. self.consumer_group = consumer_group
  15. self.topic = topic
  16. self.producer = Producer({'bootstrap.servers': self.bootstrap_servers})
  17. self.consumer = Consumer({
  18. 'bootstrap.servers': self.bootstrap_servers,
  19. 'group.id': self.consumer_group,
  20. 'auto.offset.reset': 'earliest',
  21. # 'enable.auto.commit': False # 禁用自动提交,使用手动提交
  22. 'enable.auto.commit': True
  23. })
  24. def delivery_report(self, err, msg):
  25. """
  26. 回调函数,用于确认消息是否成功发送
  27. """
  28. if err is not None:
  29. print(f"Message delivery failed: {err}")
  30. else:
  31. print(f"Message delivered to {msg.topic()} [{msg.partition()}] @ {msg.offset()}")
  32. def produce_messages(self, messages):
  33. """
  34. 发送消息
  35. """
  36. try:
  37. for message in messages:
  38. self.producer.produce(self.topic, value=message, callback=self.delivery_report)
  39. print(f"Produced: {message}")
  40. self.producer.poll(0)
  41. except Exception as e:
  42. print(f"An error occurred: {e}")
  43. finally:
  44. self.producer.flush()
  45. def produce_message(self, message):
  46. """
  47. 发送消息
  48. """
  49. try:
  50. self.producer.produce(self.topic, value=message, callback=self.delivery_report)
  51. # print(f"Produced: {message}")
  52. self.producer.poll(0)
  53. except Exception as e:
  54. print(f"An error occurred: {e}")
  55. finally:
  56. self.producer.flush()
  57. def consume_messages(self,process_callback):
  58. """
  59. 消费消息并调用回调处理业务逻辑,只有当回调返回 True 时才提交偏移量
  60. :param process_callback: 业务逻辑回调函数,返回布尔值
  61. :param user_nickname: 用户昵称
  62. """
  63. self.consumer.subscribe([self.topic])
  64. try:
  65. while True:
  66. msg = self.consumer.poll(0.3)
  67. if msg is None:
  68. continue
  69. if msg.error():
  70. if msg.error().code() == KafkaError._PARTITION_EOF:
  71. print(f"End of partition {msg.partition}, offset {msg.offset()}")
  72. else:
  73. raise KafkaException(msg.error())
  74. else:
  75. # 调用业务处理逻辑
  76. # process_callback(msg.value().decode('utf-8'))
  77. # 调用业务处理逻辑,传递 user_nickname 和消息
  78. process_callback(msg.value().decode('utf-8'))
  79. # if process_callback(user_nickname, msg.value().decode('utf-8')):
  80. # # 如果返回 True,表示处理成功,可以提交偏移量
  81. # try:
  82. # # self.consumer.commit(msg)
  83. # self.consumer.commit(message=msg, asynchronous=True)
  84. # print(f"Manually committed offset: {msg.offset()}")
  85. # except KafkaException as e:
  86. # print(f"Error committing offset: {e}")
  87. except KeyboardInterrupt:
  88. print("消费中断")
  89. finally:
  90. self.consumer.close()
  91. def consume_messages(self,agent_tel,process_callback):
  92. """
  93. 消费消息并调用回调处理业务逻辑,只有当回调返回 True 时才提交偏移量
  94. :param process_callback: 业务逻辑回调函数,返回布尔值
  95. :param agent_tel: 代理商手机号
  96. """
  97. consumer=Consumer({
  98. 'bootstrap.servers': self.bootstrap_servers,
  99. 'group.id': f'aiops-wx_{agent_tel}',
  100. 'auto.offset.reset': 'earliest',
  101. # 'enable.auto.commit': False # 禁用自动提交,使用手动提交
  102. 'enable.auto.commit': True
  103. })
  104. consumer.subscribe([self.topic])
  105. try:
  106. while True:
  107. msg = consumer.poll(0.3)
  108. if msg is None:
  109. continue
  110. if msg.error():
  111. if msg.error().code() == KafkaError._PARTITION_EOF:
  112. print(f"End of partition {msg.partition}, offset {msg.offset()}")
  113. else:
  114. raise KafkaException(msg.error())
  115. else:
  116. # 调用业务处理逻辑
  117. # process_callback(msg.value().decode('utf-8'))
  118. # 调用业务处理逻辑,传递 user_nickname 和消息
  119. process_callback(agent_tel,msg.value().decode('utf-8'))
  120. # if process_callback(user_nickname, msg.value().decode('utf-8')):
  121. # # 如果返回 True,表示处理成功,可以提交偏移量
  122. # try:
  123. # # self.consumer.commit(msg)
  124. # self.consumer.commit(message=msg, asynchronous=True)
  125. # print(f"Manually committed offset: {msg.offset()}")
  126. # except KafkaException as e:
  127. # print(f"Error committing offset: {e}")
  128. except KafkaException as e:
  129. print(f"Kafka exception occurred: {e}")
  130. if 'KafkaError._ALL_BROKERS_DOWN' in str(e):
  131. print(f"Kafka brokers for agent {agent_tel} are down, retrying in 5 seconds...")
  132. time.sleep(5)
  133. self._reconnect_consumer_with_agent_tel(consumer, agent_tel)
  134. except Exception as e:
  135. print(f"An unexpected error occurred: {e}")
  136. time.sleep(5)
  137. def _reconnect_consumer_with_agent_tel(self, consumer, agent_tel):
  138. """
  139. 尝试为指定的代理商重新连接 Kafka 消费者
  140. """
  141. print(f"Attempting to reconnect Kafka consumer for agent {agent_tel}...")
  142. try:
  143. consumer.close() # Close the old consumer
  144. consumer = Consumer({
  145. 'bootstrap.servers': self.bootstrap_servers,
  146. 'group.id': f'aiops-wx_{agent_tel}',
  147. 'auto.offset.reset': 'earliest',
  148. 'enable.auto.commit': True
  149. })
  150. consumer.subscribe([self.topic])
  151. print(f"Reconnected successfully for agent {agent_tel}.")
  152. except KafkaException as e:
  153. print(f"Error while reconnecting for agent {agent_tel}: {e}")
  154. time.sleep(5) # Retry after 5 seconds
  155. def start():
  156. global kafka_client
  157. kafka_client = KafkaClient()