https://github.com/pjfanning/pekko-rabbitmq
RabbitMq client using Scala and Pekko actors
https://github.com/pjfanning/pekko-rabbitmq
pekko rabbitmq
Last synced: 3 months ago
JSON representation
RabbitMq client using Scala and Pekko actors
- Host: GitHub
- URL: https://github.com/pjfanning/pekko-rabbitmq
- Owner: pjfanning
- License: other
- Created: 2023-07-16T12:14:06.000Z (almost 2 years ago)
- Default Branch: main
- Last Pushed: 2024-09-16T23:55:28.000Z (8 months ago)
- Last Synced: 2025-02-03T14:01:36.382Z (3 months ago)
- Topics: pekko, rabbitmq
- Language: Scala
- Homepage:
- Size: 288 KB
- Stars: 2
- Watchers: 2
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Pekko RabbitMQ client
This small library allows you to use [RabbitMQ client](https://www.rabbitmq.com/java-client.html) via [Apache Pekko Actors](https://pekko.apache.org).
This is a fork of [pjfanning/akka-rabbitmq](https://github.com/pjfanning/akka-rabbitmq), which itself is a fork of
[NewMotion/akka-rabbitmq](https://github.com/NewMotion/akka-rabbitmq).It gives you two actors `ConnectionActor` and `ChannelActor`.
### ConnectionActor
* handles connection failures and notifies children
* keep trying to reconnect if connection lost
* provides children with new channels when needed### ChannelActor
* may store messages in memory if channel lost
* send stored messages as soon as new channel received
* retrieve new channel if current is brokenPlease note that while this library transparently reconnects when a connection fails, it **cannot guarantee** that no
messages will be lost. If you want to make sure every message is delivered, you have to use acknowledgements
and confirms. This is documented
[in the RabbitMQ Reliability Guide](https://www.rabbitmq.com/reliability.html#connection-failures). An example program
using confirms can be found in this project under [ConfirmsExample.scala](https://github.com/pjfanning/pekko-rabbitmq/blob/main/src/test/scala/com/github/pjfanning/pekko/rabbitmq/examples/ConfirmsExample.scala).## Setup
### Sbt
``` scala
libraryDependencies += "com.github.pjfanning" %% "pekko-rabbitmq" % "7.0.0"
```### Maven
```xmlcom.github.pjfanning
pekko-rabbitmq_{2.12/2.13/3}
7.0.0```
## Tutorial in comparisons
Before start, you need to add import statement```scala
import com.github.pjfanning.pekko.rabbitmq._
```### Create connection
Default approach:
```scala
val factory = new ConnectionFactory()
val connection: Connection = factory.newConnection()
```Actor style:
```scala
val factory = new ConnectionFactory()
val connectionActor: ActorRef = system.actorOf(ConnectionActor.props(factory))
```Let's name it:
```scala
system.actorOf(ConnectionActor.props(factory), "my-connection")
```How often will it reconnect?
```scala
import concurrent.duration._
system.actorOf(ConnectionActor.props(factory, reconnectionDelay = 10.seconds), "my-connection")
```### Create channel
That's plain option:
```scala
val channel: Channel = connection.createChannel()
```But we can do better. Asynchronously:
```scala
connectionActor ! CreateChannel(ChannelActor.props())
```Synchronously:
```scala
val channelActor: ActorRef = connectionActor.createChannel(ChannelActor.props())
```Maybe give it a name:
```scala
connectionActor.createChannel(ChannelActor.props(), Some("my-channel"))
```What's about custom actor:
```scala
connectionActor.createChannel(Props(new Actor {
def receive = {
case channel: Channel =>
}
}))
```### Setup channel
```scala
channel.queueDeclare("queue_name", false, false, false, null)
```Actor style:
```scala
// this function will be called each time new channel received
def setupChannel(channel: Channel, self: ActorRef) = {
channel.queueDeclare("queue_name", false, false, false, null)
}
val channelActor: ActorRef = connectionActor.createChannel(ChannelActor.props(setupChannel))
```### Use channel
```scala
channel.basicPublish("", "queue_name", null, "Hello world".getBytes)
```Using our `channelActor`:
```scala
def publish(channel: Channel) = {
channel.basicPublish("", "queue_name", null, "Hello world".getBytes)
}
channelActor ! ChannelMessage(publish)
```But I don't want to lose messages when connection is lost:
```scala
channelActor ! ChannelMessage(publish, dropIfNoChannel = false)
```### Close channel
```scala
channel.close()
```
VS
```scala
system stop channelActor
```### Close connection
```scala
connection.close()
```
VS
```scala
system stop connectionActor // will close all channels associated with this connection
```You can shutdown `ActorSystem`, this will close all connections as well as channels:
```scala
system.shutdown()
```## Examples:
### Publish/Subscribe
Here is [RabbitMQ Publish/Subscribe](http://www.rabbitmq.com/tutorials/tutorial-three-java.html) in actors style
```scala
import org.apache.pekko.actor.ActorSystem
object PublishSubscribe extends App {
implicit val system: ActorSystem = ActorSystem()
val factory = new ConnectionFactory()
val connection = system.actorOf(ConnectionActor.props(factory), "pekko-rabbitmq")
val exchange = "amq.fanout"def setupPublisher(channel: Channel, self: ActorRef) = {
val queue = channel.queueDeclare().getQueue
channel.queueBind(queue, exchange, "")
}
connection ! CreateChannel(ChannelActor.props(setupPublisher), Some("publisher"))def setupSubscriber(channel: Channel, self: ActorRef) = {
val queue = channel.queueDeclare().getQueue
channel.queueBind(queue, exchange, "")
val consumer = new DefaultConsumer(channel) {
override def handleDelivery(consumerTag: String, envelope: Envelope, properties: BasicProperties, body: Array[Byte]): Unit = {
println("received: " + fromBytes(body))
}
}
channel.basicConsume(queue, true, consumer)
}
connection ! CreateChannel(ChannelActor.props(setupSubscriber), Some("subscriber"))Future {
def loop(n: Long) = {
val publisher = system.actorSelection("/user/pekko-rabbitmq/publisher")def publish(channel: Channel) = {
channel.basicPublish(exchange, "", null, toBytes(n))
}
publisher ! ChannelMessage(publish, dropIfNoChannel = false)Thread.sleep(1000)
loop(n + 1)
}
loop(0)
}def fromBytes(x: Array[Byte]) = new String(x, "UTF-8")
def toBytes(x: Long) = x.toString.getBytes("UTF-8")
}
```
## Testing NoteTests can be run against a RabbitMQ server on the local machine using a Docker container with
the following command. The RabbitMQ console can be accessible also with http://localhost:8080
using the login and password of guest and guest.docker run -d -p:5672:5672 rabbitmq:3
## Changelog
[Releases](https://github.com/pjfanning/pekko-rabbitmq/releases)
## Other Libraries
Pekko-RabbitMQ is a low-level library, and leaves it to the coder to manually wire consumers, serialize messages, etc. If you'd like a higher-level abstraction library, look at
[Op-Rabbit](https://github.com/pjfanning/op-rabbit.git).