lapin

repository·main·Indexed 22 days ago

https://github.com/amqp-rs/lapin

An asynchronous AMQP 0-9-1 client library for Rust, specifically designed for interacting with RabbitMQ. Version 4.10.0 is runtime-agnostic, supporting Tokio, Smol, and async-global-executor. It provides features for automatic connection and topology recovery, configurable TLS backends (rustls, native-tls, openssl), and a thread-safe Channel API for declaring exchanges, publishing messages, and consuming from queues.

Tokens
8.2K
Snippets
11
Records
48
Agent score
79%

What's inside lapin

  1. Enable automatic connection recovery

    main

    You can configure lapin to automatically reconnect and replay exchanges, queues, bindings, and consumers after a network failure by calling .enable_auto_recover() on ConnectionProperties.

    If you encounter a recoverable error on a channel, you can block until the recovery process is complete by calling channel.wait_for_recovery(error).await.

    use lapin::ConnectionProperties;
    
    let props = ConnectionProperties::default().enable_auto_recover();
  2. Quick start with lapin

    main

    To get started with lapin, connect to an AMQP broker, create a channel, declare a queue, publish a message, and consume messages. This example uses tokio as the async runtime and futures_lite for stream processing.

    use futures_lite::stream::StreamExt;
    use lapin::{
        options::*,
        types::FieldTable,
        BasicProperties,
        Connection,
        ConnectionProperties,
        Result,
    };
    
    #[tokio::main]
    async fn main() -> Result<()> {
        let addr = std::env::var("AMQP_ADDR")
            .unwrap_or_else(|_| "amqp://127.0.0.1:5672/%2f".into());
    
        let conn = Connection::connect(&addr, ConnectionProperties::default()).await?;
        let channel = conn.create_channel().await?;
    
        channel
            .queue_declare("hello".into(), QueueDeclareOptions::durable(), FieldTable::default())
            .await?;
    
        channel
            .basic_publish(
                "".into(),
                "hello".into(),
                BasicPublishOptions::default(),
                b"Hello, world!",
                BasicProperties::default(),
            )
            .await?
            .await?;
    
        let mut consumer = channel
            .basic_consume(
                "hello".into(),
                "my_consumer".into(),
                BasicConsumeOptions::default(),
                FieldTable::default(),
            )
            .await?;
    
        while let Some(delivery) = consumer.next().await {
            let delivery = delivery?;
            delivery.ack(BasicAckOptions::default()).await?;
        }
        Ok(())
    }
  3. Implement custom consumer logic with ConsumerDelegate

    main

    If you prefer a callback-based approach over polling the Consumer stream, you can implement the ConsumerDelegate trait. This allows you to have deliveries dispatched automatically.

    To use it, implement the trait and pass your instance to Consumer::set_delegate. This method enables parallel handling of messages by spawning the delegate on the executor for each message.

    Trait Methods

    • on_new_delivery(&self, delivery: DeliveryResult) -> Pin<Box<dyn Future<Output = ()> + Send>>: Called for each new delivery, cancellation, or error from the server.
    • drop_prefetched_messages(&self) -> Pin<Box<dyn Future<Output = ()> + Send>>: (Optional) Called when the consumer is asked to discard buffered messages (e.g., on channel close).
  4. Use the Channel API for AMQP operations

    main

    The Channel struct is the primary entry point for most AMQP operations, such as declaring exchanges, publishing messages, and consuming from queues. While the AMQP specification suggests one channel per OS thread, Channel in lapin is Clone + Send + Sync. This means you can safely clone a Channel and use the clones across different asynchronous tasks or OS threads.

    Channels are typically obtained from a Connection using Connection::create_channel.

  5. Determine if an error can be recovered

    main

    The can_be_recovered() method indicates whether the error is of a type that the automatic recovery logic can attempt to handle. This is used internally by the auto-recovery logic and requires ConnectionProperties::enable_auto_recover to be set.

    Recoverable errors:

    • InvalidChannel
    • InvalidChannelState
    • InvalidConnectionState
    • IOError
    • ProtocolError
    • MissingHeartbeatError

    Non-recoverable errors:

    • ChannelsLimitReached
    • InvalidProtocolVersion
    • RuntimeShutdownError
    • ParsingError
    • SerialisationError
    • AuthProviderError
    • FutureCompleted
    • NoDefaultRuntime
  6. Track message delivery status with PublisherConfirm

    main

    When you call Channel::basic_publish, it returns a PublisherConfirm future. This future resolves to a Confirmation enum, which indicates whether the broker successfully received and processed the message.

    Important Lifecycle Note: If you drop a PublisherConfirm without awaiting it, the library automatically registers it with Channel::wait_for_confirms to ensure that confirmations are not silently lost. This prevents a common race condition where a developer might assume a message was sent successfully simply because they didn't encounter an error during the publish call.

  7. Configure async runtimes

    main

    Lapin is runtime-agnostic. You must pick exactly one async runtime feature flag during installation:

    FlagNotes
    tokio (default)Requires a running Tokio runtime
    smolUses the smol executor
    async-global-executorUses async-global-executor
  8. Understand ConnectionState lifecycle

    main

    The ConnectionState enum represents the various stages of an AMQP connection's lifecycle. Monitoring these states allows you to implement logic for handling reconnections, errors, or graceful shutdowns.

    Connection States

    • Initial: The connection object is created, but the TCP handshake hasn't started.
    • Connecting: The TCP connection is open and the AMQP handshake is in progress.
    • Connected: The AMQP handshake completed successfully; the connection is ready for use.
    • Closing: A Connection.Close frame has been sent; waiting for Connection.Close-Ok.
    • Closed: The connection has been closed normally.
    • Reconnecting: The connection was lost and is being re-established via automatic recovery.
    • Error: The connection was closed due to a protocol or IO error.
  9. How Connection, Channel, and Consumer work together

    main

    The lapin library follows the standard AMQP hierarchy:

    1. Connection: A single TCP socket to the broker. Typically, one process creates one connection and reuses it.
    2. Channel: A lightweight virtual connection multiplexed over a Connection. All AMQP operations (declaring queues, publishing, consuming, etc.) are performed through channels. They are cheap to open.
    3. Consumer: An async Stream of message::Delivery values obtained by calling Channel::basic_consume. Each delivery must be explicitly acknowledged (e.g., via delivery.ack(...)) once processed.
    4. PublisherConfirm: A future returned by Channel::basic_publish that resolves to a Confirmation once the broker has acknowledged the message. This requires calling Channel::confirm_select first.
  10. Configure Rustls certificate stores

    main

    When the rustls feature is active, you can choose a certificate store via these flags:

    FlagNotes
    rustls-platform-verifier (default)Platform trust store
    rustls-native-certsNative root certificates
    rustls-webpki-roots-certsBundled webpki root set