-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
DamirDenis-Tudor
committed
Dec 14, 2024
1 parent
0a64f46
commit 98f5a82
Showing
6 changed files
with
240 additions
and
41 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,40 +1,205 @@ | ||
# kabbitmq | ||
# ![Ktor](https://avatars.githubusercontent.com/u/28214161?s=40&v=4.svg) KabbitMQ | ||
|
||
This project was created using the [Ktor Project Generator](https://start.ktor.io). | ||
## Overview | ||
|
||
Here are some useful links to get you started: | ||
- `kabbitmq` is a Ktor plugin for RabbitMQ that provides access to all the core functionalities of the Java RabbitMQ Client library. It integrates seamlessly with Ktor's DSL, offering readable, maintainable, and easy-to-use functionalities. | ||
|
||
- [Ktor Documentation](https://ktor.io/docs/home.html) | ||
- [Ktor GitHub page](https://github.com/ktorio/ktor) | ||
- The [Ktor Slack chat](https://app.slack.com/client/T09229ZC6/C0A974TJ9). You'll need | ||
to [request an invite](https://surveys.jetbrains.com/s3/kotlin-slack-sign-up) to join. | ||
|
||
## Features | ||
|
||
Here's a list of features included in this project: | ||
### Gradle (Kotlin DSL) - dependencies | ||
|
||
| Name | Description | | ||
| ----------------------------------------------------|------------------------------------------------------------- | | ||
| [Routing](https://start.ktor.io/p/routing-default) | Allows to define structured routes and associated handlers. | | ||
```kotlin | ||
dependencies { | ||
implementation("io.github.damirdenis-tudor:kabbitmq:0.2.0") | ||
} | ||
``` | ||
|
||
### Installation | ||
|
||
```kotlin | ||
install(KabbitMQ) { | ||
uri = "amqp://guest:guest@localhost:5678" | ||
connectionName = "guest" | ||
} | ||
``` | ||
|
||
### Features | ||
- DSL wrapper for almost all the functionalities with parameter validation. | ||
- Channel & Connection management mechanism. | ||
- Built in message serialization and deserialization. | ||
- Possibility to interact directly with Java RabbitMQ Client Library. | ||
|
||
### Samples | ||
|
||
#### Channel management sample | ||
```kotlin | ||
/* default connection with default channel */ | ||
consumerCount { queue = "test-queue" } | ||
|
||
/* default connection with new channel */ | ||
channel( | ||
id = "intensive", | ||
autoClose = false /* can be reused by id */ | ||
){ | ||
consumerCount { queue = "test-queue" } | ||
} | ||
``` | ||
|
||
#### Connection management sample | ||
```kotlin | ||
/* new connection with new channels */ | ||
connection( | ||
id = "intensive", | ||
autoClose = false /* can be reused by id */ | ||
) { /* channels will be terminated after task completion */ | ||
channel { | ||
messageCount { queue = "test-queue" } | ||
} | ||
channel { | ||
basicConsume { | ||
queue = "test-queue" | ||
autoAck = true | ||
deliverCallback<Message> { tag, message -> | ||
println("Message: $message with $tag") | ||
} | ||
} | ||
} | ||
} | ||
``` | ||
|
||
#### Strongly type code style sample | ||
|
||
## Building & Running | ||
|
||
To build or run the project, use one of the following tasks: | ||
```kotlin | ||
/* | ||
* In RabbitMQ client you have overloaded functions and in order to maintain compatibility | ||
* with DSL style a mechanism for parameter validation is required. | ||
* The core of this mechanism is a custom state delegator mechanism. | ||
*/ | ||
|
||
| Task | Description | | ||
| -------------------------------|---------------------------------------------------------------------- | | ||
| `./gradlew test` | Run the tests | | ||
| `./gradlew build` | Build everything | | ||
| `buildFatJar` | Build an executable JAR of the server with all dependencies included | | ||
| `buildImage` | Build the docker image to use with the fat JAR | | ||
| `publishImageToLocalRegistry` | Publish the docker image locally | | ||
| `run` | Run the server | | ||
| `runDocker` | Run using the local docker image | | ||
basicConsume { | ||
queue = "test-queue" | ||
/* autoAck = true */ // let's say that autoAck is omited | ||
deliverCallback<Message> { tag, message -> | ||
println("Message: $message with $tag") | ||
} | ||
} | ||
``` | ||
|
||
If the server starts successfully, you'll see the following output: | ||
```log | ||
2024-12-14 18:29:26.015 [DefaultDispatcher-worker-1] WARN KabbitMQBasicConsumeBuilder - <arguments>, initialized: <true> | ||
2024-12-14 18:29:26.015 [DefaultDispatcher-worker-1] WARN KabbitMQBasicConsumeBuilder - <autoAck>, initialized: <false> | ||
2024-12-14 18:29:26.015 [DefaultDispatcher-worker-1] WARN KabbitMQBasicConsumeBuilder - <cancelCallback>, initialized: <true> | ||
2024-12-14 18:29:26.015 [DefaultDispatcher-worker-1] WARN KabbitMQBasicConsumeBuilder - <channel>, initialized: <false> | ||
2024-12-14 18:29:26.015 [DefaultDispatcher-worker-1] WARN KabbitMQBasicConsumeBuilder - <consumerTag>, initialized: <false> | ||
2024-12-14 18:29:26.015 [DefaultDispatcher-worker-1] WARN KabbitMQBasicConsumeBuilder - <deliverCallback>, initialized: <true> | ||
2024-12-14 18:29:26.015 [DefaultDispatcher-worker-1] WARN KabbitMQBasicConsumeBuilder - <exclusive>, initialized: <true> | ||
2024-12-14 18:29:26.015 [DefaultDispatcher-worker-1] WARN KabbitMQBasicConsumeBuilder - <noLocal>, initialized: <true> | ||
2024-12-14 18:29:26.015 [DefaultDispatcher-worker-1] WARN KabbitMQBasicConsumeBuilder - <queue>, initialized: <true> | ||
2024-12-14 18:29:26.015 [DefaultDispatcher-worker-1] WARN KabbitMQBasicConsumeBuilder - <shutdownSignalCallback>, initialized: <false> | ||
java.lang.IllegalStateException: Unsupported combination of parameters for basicConsume. | ||
``` | ||
2024-12-04 14:32:45.584 [main] INFO Application - Application started in 0.303 seconds. | ||
2024-12-04 14:32:45.682 [main] INFO Application - Responding at http://0.0.0.0:8080 | ||
|
||
#### Direct interaction with libray sample | ||
|
||
|
||
```kotlin | ||
channel("direct-calls"){ | ||
basicPublish("test", "test-routing-key", null, "fdsf".toByteArray()) | ||
|
||
val consumer = object : DefaultConsumer(channel) { | ||
override fun handleDelivery( | ||
consumerTag: String?, | ||
envelope: Envelope?, | ||
properties: AMQP.BasicProperties?, | ||
body: ByteArray? | ||
) { | ||
println("Received message: ${body?.let { String(it) }}") | ||
} | ||
} | ||
basicConsume(queueName, true, consumer) | ||
} | ||
``` | ||
|
||
|
||
## Dead Letter Queue Example | ||
|
||
```kotlin | ||
@Serializable | ||
data class Message( | ||
var content: String | ||
) | ||
|
||
fun Application.queueBinding() { | ||
install(KabbitMQ) { | ||
uri = "amqp://guest:guest@localhost:5678" | ||
connectionName = "guest" | ||
} | ||
|
||
// declare dead letter queue | ||
queueBind { | ||
queue = "dlq" | ||
exchange = "dlx" | ||
routingKey = "dlq-dlx" | ||
queueDeclare { | ||
queue = "dlq" | ||
durable = true | ||
} | ||
exchangeDeclare { | ||
exchange = "dlx" | ||
type = BuiltinExchangeType.DIRECT | ||
} | ||
} | ||
|
||
// declare queue configured with dead letter queue | ||
queueBind { | ||
queue = "test-queue" | ||
exchange = "test-exchange" | ||
queueDeclare { | ||
queue = "test-queue" | ||
arguments = mapOf( | ||
"x-dead-letter-exchange" to "dlx", | ||
"x-dead-letter-routing-key" to "dlq-dlx" | ||
) | ||
} | ||
exchangeDeclare { | ||
exchange = "test-exchange" | ||
type = BuiltinExchangeType.FANOUT | ||
} | ||
} | ||
|
||
repeat(10) { | ||
basicPublish { | ||
exchange = "test-exchange" | ||
message { | ||
Message(content = "Hello world!") | ||
} | ||
} | ||
} | ||
|
||
basicConsume { | ||
queue = "test-queue" | ||
autoAck = false | ||
deliverCallback<Message> { tag, message -> | ||
/* process message */ | ||
// ... | ||
|
||
/* simulate something went wrong */ | ||
basicReject { | ||
deliveryTag = tag | ||
requeue = false | ||
} | ||
} | ||
} | ||
|
||
basicConsume { | ||
queue = "dlq" | ||
autoAck = true | ||
deliverCallback<Message> { _, message -> | ||
/* process message */ | ||
println("Message in DLQ: $message") | ||
} | ||
} | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.