코드
Github의 주소 : HTTPS : //github.com/HanseyLee/RabbitMQClient
#!/usr/bin/python
# -*- coding:utf-8 -*-
import pika
import hashlib
import json
def getMd5(input_str):
"""
:param str input_str: Unicode-objects must be encoded before hashing
:rtype: str
"""
hash_obj = hashlib.md5(input_str.encode("utf-8"))
return hash_obj.hexdigest()
class RabbitMQClient:
"""RabbitMQClient using pika library
default: exchange type is 'topic', routing key is '#', dead letter exchange is 'DLX' and dead letter queue is 'DLQ'.
"""
__default_exchange_type = "topic"
# (hash) can substitute for zero or more words, * (star) can substitute for exactly one word.
__default_routing_key = "#"
__default_DeadLetterExchange = "DLX"
__default_DeadLetterQueue = "DLQ"
def __init__(self, username, password, host, port=5672):
self.host = str(host)
self.port = int(port)
# set heartbeat=0, deactivate heartbeat default
self.connection = pika.BlockingConnection(pika.ConnectionParameters(host=self.host,
port=self.port, credentials=pika.PlainCredentials(username,password), heartbeat=0))
self.channel = self.connection.channel()
#
# basic operations
#
def close_connection(self):
self.connection.close()
def declare_exchange(self, exchange, exchange_type=__default_exchange_type):
self.channel.exchange_declare(exchange=exchange, exchange_type=exchange_type, durable=True)
def delete_exchange(self, exchange):
self.channel.exchange_delete(exchange=exchange)
def declare_queue(self, queue):
self.channel.queue_declare(queue=queue, durable=True)
def declare_queue_dlx(self, queue, dlx=__default_DeadLetterQueue):
self.channel.queue_declare(queue=queue, durable=True, arguments={'x-dead-letter-exchange': dlx})
def declare_queue_ttl(self, queue, ttl_seconds):
self.channel.queue_declare(queue=queue, durable=True, arguments={'x-message-ttl': ttl_seconds})
def delete_queue(self, queue):
self.channel.queue_delete(queue=queue)
def bind_exchange_queue(self, queue, exchange, binding_key=__default_routing_key):
self.channel.queue_bind(queue=queue, exchange=exchange, routing_key=binding_key)
#
# combined operations
#
def declare_dlx_dlq(self, dlx=__default_DeadLetterExchange, dlq=__default_DeadLetterQueue):
"""
:param str dlx: dead letter exchange
:param str dlq: dead letter queue
"""
self.declare_exchange(exchange=dlx, exchange_type='fanout')
self.declare_queue(queue=dlq)
self.bind_exchange_queue(exchange=dlx, queue=dlq)
def publish(self, message, exchange, queue, routing_key, message_id=None,
close_connection=True):
"""
publish messages with message_id, disk persistency property
"""
if message_id is None:
message_id = getMd5(input_str=message)
self.declare_queue(queue=queue)
self.channel.basic_publish(exchange=exchange, routing_key=routing_key, body=message,
properties=pika.BasicProperties(delivery_mode=2,message_id=message_id,content_type="application/json"))
if close_connection:
self.close_connection()
def consume(self, callback, queue, dlx=__default_DeadLetterExchange, dlq=__default_DeadLetterQueue,
exclusive=False, consumer_tag=None,**kwargs):
self.declare_dlx_dlq(dlx=dlx, dlq=dlq)
self.channel.basic_consume(queue=queue, on_message_callback=callback, exclusive=exclusive,
consumer_tag=consumer_tag,**kwargs)
try:
self.channel.start_consuming()
except KeyboardInterrupt:
self.channel.stop_consuming()
self.close_connection()
@staticmethod
def ack_message(channel, method):
channel.basic_ack(delivery_tag=method.delivery_tag)
@staticmethod
def reject_to_dlx(channel, method):
"""
need the queue from which message is consuming has dead letter exchage property
"""
channel.basic_reject(delivery_tag=method.delivery_tag, requeue=False)
@staticmethod
def transmit(channel, method, properties, message, exchange=__default_DeadLetterExchange,
routing_key=__default_routing_key, queue=__default_DeadLetterQueue,handler=None):
if handler is not None:
message = handler(message)
message_id = properties.message_id
if message_id is None:
message_id = getMd5(input_str=message)
channel.basic_publish(exchange=exchange, routing_key=routing_key, body=message,
properties=pika.BasicProperties(delivery_mode=2,message_id=message_id,content_type="application/json"))
channel.basic_ack(delivery_tag=method.delivery_tag)
#
### Testing
#
def callback(ch, method, properties, body):
print("consumer_tag %r, consume_func %r, %r" % (method.consumer_tag, method.routing_key, properties.message_id))
# RabbitMQClient.transmit(channel=ch, method=method, properties=properties, message=str(body, 'utf-8'), handler=handler)
RabbitMQClient.ack_message(channel=ch, method=method)
def handler(input_str):
return "hadled"+input_str
if __name__ == "__main__":
mqc = RabbitMQClient(username='xxx',password='xxx',host='xxx',port=5672)
msg = json.dumps({'a':'aaa'})
queue = "DLQ"
# mqc.publish(message=msg, exchange='', routing_key=queue, queue=queue)
# mqc.consume(callback=callback, queue=queue, consumer_tag='consumer-1')
print("==done==")
참고
https://stackoverflow.com/questions/18418936/rabbitmq-and-relationship-between-channel-and-connection
https://www.rabbitmq.com/tutorials/tutorial-five-python.html
주의
- 연결
- 메시지 브로커에 실제 TCP 연결은, 오래 지속 할 수 있도록 설계되어있다.
- 설정 연결 속성 하트 비트 = 0, 연결 시간이 초과되지 않도록, 그것을 유지, 심장 박동을 비활성화합니다.
- 채널
- 디자인 연결 내부 가상 연결 (AMPQ 연결), 과도합니다.
- 소비자 다음 채널을 설정
- 채널 인스턴스는 쓰레드간에 공유 할 수 없습니다. 채널은 일반적으로 스레드 안전하지 않습니다이 스레드간에 공유하는 것은 의미가 없습니다로. 브로커를 사용할 필요가 다른 스레드가있는 경우, 새로운 채널이 필요하다.
- 교환, Routing_key, 대기열
- 교환 --- Routing_key ---> 대기열
- 교환의 형태로 주제는 거의 모든 다른 모드를 시뮬레이션 할 수 있습니다.
-
- (스타) 정확히 하나 개의 단어를 대체 할 수 있습니다. # (해시)는 0 개 이상의 단어를 대체 할 수 있습니다.
- 특수 문자 "*"(별표) 및 "#"(해시) 바인딩을 사용하지 않을 때, 주제 교환은 직접처럼 => 직접 模式을 작동합니다
- 큐는 "#"(해시) 키 바인딩과 결합하는 경우 - 그것은 팬 아웃 교환처럼 => 라우팅 키에 관계없이 모든 메시지를 받게됩니다
-
- 큐 특성, 소정 시간을 설정 한 후, 상기 메시지 큐는 자동으로 제거되고, 장치가 더 TTL (생균 시간)를 제공 할 수있다.
queue_declare(queue=queue, durable=True, arguments={'x-message-ttl': ttl_seconds})
- 발행자
- 릴리스는 소비하기 전에 Exchange 큐 메시지를 선언해야합니다.
- 각 메시지는, 타점 비즈니스 추적을 쉽게 따라, 해당 속성을 설정 MESSAGE_ID 좋습니다.
- 소비자
- 더 많은 소비자 라운드 로빈 (RR) 스케줄링 소비자 박람회
- 각 소비자는 소비자 스레드 풀에서 할당 자체 스레드에서 실행됩니다. 다수의 소비자가 (다른 channnels에서) 동일한 대기열에 가입하는 경우, 브로커는 동등하게 그들 사이에 메시지를 배포하는 라운드 로빈을 사용합니다.
- (: 죽은 편지 교환, DLQ DLX 소비자에 해당하는, 소비와 죽은 편지 큐의 메시지를 전 deadletter 기 지정하는 것이 바람직하다 : 죽은 편지 큐). 소비 과정에서 메시지는 해결할 수없는, 이상은 DLX 및 DLQ에 전달 될 수있다. 또한 전달하기 전에 메시지의 고유의 처리 및 포장을 할 수 있습니다. 문이 큐를 지정한 경우 DLX의 같은 속성 때 (
arguments={'x-dead-letter-exchange': dlx}
소비자의, 소비자가 직접 메시지를 거부 메시지가 혜택을 전달 로직을 작성하지 않도록, 단점은 충분히 할 수없는 유연하지의 DLX에 직접 거부됩니다 메시지가 처리되고 패키지화된다.)
- 더 많은 소비자 라운드 로빈 (RR) 스케줄링 소비자 박람회
<끝>
참고 : 같은 이름을 CSDN 블로그의 콘텐츠 동기화 : HTTPS : //blog.csdn.net/fzlulee/article/details/98480724