RabbitMQ 클라이언트 파이썬 새앙 토끼 간단한 패키지 라이브러리를 기반으로

코드

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에 직접 거부됩니다 메시지가 처리되고 패키지화된다.)

<끝>

참고 : 같은 이름을 CSDN 블로그의 콘텐츠 동기화 : HTTPS : //blog.csdn.net/fzlulee/article/details/98480724

추천

출처www.cnblogs.com/HanseyLee/p/11310418.html