| = JMS and JPA: A Camel Quarkus example |
| :cq-example-description: An example that shows how to run a Camel Quarkus application that supports JTA transactions on three external transactional resources: a database (MySQL), a messaging broker (Artemis) and a simulated XAResource which can demonstrate the commit, rollback and crash recovery. |
| |
| {cq-description} |
| |
| We use Narayana as the standalone JTA Transaction Manager implementation, and Hibernate as the JPA Adapter. |
| |
| This example will connect to a database with the connection details defined in `application.properties`. |
| If the example is run on Development mode and no database exists, Quarkus will create a matching database |
| https://quarkus.io/guides/datasource#dev-services[as described here]. |
| |
| TIP: Check the https://camel.apache.org/camel-quarkus/latest/first-steps.html[Camel Quarkus User guide] for prerequisites |
| and other general information. |
| |
| NOTE: The Narayana `node.identifier` is very important when you scale up in the cloud environment. It must be unique for each node. You can set it by using `quarkus.transaction-manager.node-name` property which the default value is `quarkus`. |
| |
| == Start in the Development mode |
| |
| [source,shell] |
| ---- |
| $ mvn clean compile quarkus:dev |
| ---- |
| |
| The above command compiles the project, starts the application and lets the Quarkus tooling watch for changes in your |
| workspace. Any modifications in your project will automatically take effect in the running application. |
| |
| TIP: Please refer to the Development mode section of |
| https://camel.apache.org/camel-quarkus/latest/first-steps.html#_development_mode[Camel Quarkus User guide] for more details. |
| |
| == Package and run the application |
| |
| Once you are done with developing you may want to package and run the application. |
| |
| TIP: Find more details about the JVM mode and Native mode in the Package and run section of |
| https://camel.apache.org/camel-quarkus/latest/first-steps.html#_package_and_run_the_application[Camel Quarkus User guide] |
| |
| ==== External systems |
| |
| Start MySQL: |
| [source, shell] |
| ---- |
| docker run --name db-mysql \ |
| -e MYSQL_ROOT_PASSWORD=root \ |
| -d -p 3306:3306 mysql |
| |
| docker exec -it db-mysql mysql -uroot -proot -e \ |
| "CREATE DATABASE testdb CHARACTER SET utf8mb4; |
| CREATE USER 'admin'@'%' IDENTIFIED WITH mysql_native_password BY 'admin'; |
| GRANT ALL ON testdb.* TO 'admin'@'%'; |
| GRANT XA_RECOVER_ADMIN on *.* to 'admin'@'%'; |
| FLUSH PRIVILEGES;" |
| ---- |
| |
| Create `audit_log` if it is needed: |
| [source, shell] |
| ---- |
| docker exec -it db-mysql mysql -uadmin -padmin testdb -e \ |
| "CREATE TABLE audit_log ( \ |
| id bigint NOT NULL AUTO_INCREMENT, \ |
| message varchar(255) DEFAULT NULL, \ |
| PRIMARY KEY (id) \ |
| );" |
| ---- |
| |
| Start Artemis: |
| [source, shell] |
| ---- |
| docker run --name artemis \ |
| -e AMQ_USER=admin -e AMQ_PASSWORD=admin \ |
| -d -p 61616:61616 \ |
| quay.io/artemiscloud/activemq-artemis-broker |
| ---- |
| |
| |
| ==== Prerequisites |
| - Make sure `io.quarkus:quarkus-jdbc-mysql` has been added in `pom.xml` |
| - Make sure `db-mysql` and `artemis` has been started and ready for servicing |
| - Edit `src/main/resource/application.properties` to uncomment all `%prod` lines |
| [source, properties] |
| ---- |
| # Production Datasource |
| %prod.quarkus.datasource.db-kind=mysql |
| %prod.quarkus.datasource.username=admin |
| $prod.quarkus.datasource.password=admin |
| %prod.quarkus.datasource.jdbc.url=mysql://localhost:3306/testdb |
| %prod.quarkus.datasource.jdbc.transactions=xa |
| |
| %prod.quarkus.hibernate-orm.database.generation=none |
| |
| %prod.quarkus.artemis.url=tcp://localhost:61616 |
| %prod.quarkus.artemis.username=admin |
| %prod.quarkus.artemis.password=admin |
| ---- |
| |
| ==== JVM mode |
| |
| [source,shell] |
| ---- |
| $ mvn clean package |
| $ java -jar target/quarkus-app/quarkus-run.jar |
| ... |
| |
| [io.quarkus] (main) camel-quarkus-examples-... started in 0.570s. |
| ---- |
| |
| ==== Native mode |
| |
| IMPORTANT: Native mode requires having GraalVM and other tools installed. Please check the Prerequisites section |
| of https://camel.apache.org/camel-quarkus/latest/first-steps.html#_prerequisites[Camel Quarkus User guide]. |
| |
| To prepare a native executable using GraalVM, run the following command: |
| |
| [source,shell] |
| ---- |
| $ mvn clean package -Pnative |
| $ ./target/*-runner |
| ... |
| [io.quarkus] (main) camel-quarkus-examples-... started in 0.011s. |
| ... |
| ---- |
| |
| ==== How to run |
| Test the service endpoint from another terminal: |
| |
| [source,shell] |
| ---- |
| ADDRESS="http://localhost:8080" |
| curl -X POST $ADDRESS/api/messages/hello |
| curl $ADDRESS/api/messages |
| ---- |
| |
| Test with normal "hello" content: |
| [source,shell] |
| ---- |
| curl -X POST $ADDRESS/api/messages/hello |
| ---- |
| |
| Check the audit_log |
| [source,shell] |
| ---- |
| curl $ADDRESS/api/messages |
| ---- |
| You should get some results like |
| [source] |
| ---- |
| [{message=hello}, {message=hello-ok}] |
| ---- |
| |
| Test rollback by calling the service with "fail" content: |
| [source,shell] |
| ---- |
| curl -X POST $ADDRESS/api/messages/fail |
| ---- |
| You should not find any trace of the message in the audit_log table. And some failures like |
| [source] |
| ---- |
| 2022-07-01 11:03:10,257 INFO [route2] (executor-thread-0) Forced exception |
| 2022-07-01 11:03:10,257 ERROR [org.apa.cam.pro.err.DefaultErrorHandler] (executor-thread-0) Failed delivery for (MessageId: 0BE5920FE20C353-0000000000000001 on ExchangeId: 0BE5920FE20C353-0000000000000001). Exhausted after delivery attempt: 1 caught: java.lang.RuntimeException: fail |
| |
| Message History (source location and message history is disabled) |
| --------------------------------------------------------------------------------------------------------------------------------------- |
| Source ID Processor Elapsed (ms) |
| route5/route5 from[platform-http:///api/messages/%7Bmessage%7D?h 4 |
| ... |
| route2/process1 Processor@0x60941009 0 |
| |
| Stacktrace |
| ---------------------------------------------------------------------------------------------------------------------------------------: java.lang.RuntimeException: fail |
| |
| ---- |
| |
| Test crash recovery by calling the service with "crash" content: |
| [source,shell] |
| ---- |
| curl -X POST $ADDRESS/api/messages/crash |
| ---- |
| The application should be crashed, and you can not see any response. |
| [source] |
| ---- |
| curl: (52) Empty reply from server |
| ---- |
| Now restart the application, and wait about 10 seconds, then you can see the following messages that the application has recovered the transaction. |
| [source] |
| ---- |
| 2022-09-16 12:35:39,994 INFO [io.quarkus] (main) camel-quarkus-examples-jta-jpa 2.13.0-SNAPSHOT on JVM (powered by Quarkus 2.13.0.CR1) started in 1.755s. Listening on: http://0.0.0.0:8080 |
| 2022-09-16 12:35:39,994 INFO [io.quarkus] (main) Profile prod activated. |
| 2022-09-16 12:35:39,994 INFO [io.quarkus] (main) Installed features: [agroal, camel-attachments, camel-bean, camel-core, camel-direct, camel-jpa, camel-jta, camel-log, camel-microprofile-health, camel-platform-http, camel-rest, cdi, hibernate-orm, jdbc-h2, jdbc-mysql, narayana-jta, smallrye-context-propagation, smallrye-health, vertx] |
| 2022-09-16 12:35:49,251 INFO [org.acm.DummyXAResourceRecovery] (Periodic Recovery) DummyXAResourceRecovery returning list of resources: [org.acme.DummyXAResource@35cdbf7a] |
| 2022-09-16 12:35:49,270 INFO [org.acm.DummyXAResource] (Periodic Recovery) Committing DummyXAResource |
| ---- |
| check the audit_log table, you should see the message "crash" in the table. |
| |
| == Feedback |
| |
| Please report bugs and propose improvements via https://github.com/apache/camel-quarkus/issues[GitHub issues of Camel Quarkus] project. |