이 콘텐츠는 선택한 언어로 제공되지 않습니다.
Chapter 7. Running a Camel Service on Spring Boot with XA Transactions
7.1. Introduction to Camel Service on Spring Boot with XA Transactions
The Spring Boot Camel XA transactions quickstart demonstrates how to run a Camel Service on Spring-Boot that supports XA transactions on two external transactional resources, a JMS resource (A-MQ) and a database (PostgreSQL). These external resources are provided by OpenShift which must be started before running this quickstart.
7.2. StatefulSet resources
This quickstart uses OpenShift StatefulSet
resources to guarantee uniqueness of transaction managers and require a PersistentVolume to store transaction logs. The application supports scaling on the StatefulSet resource. Each instance will have its own in-process
recovery manager. A special controller guarantees that when the application is scaled down, all instances, that are terminated, complete all their work correctly without leaving pending transactions. The scale-down operation is rolled back by the controller if the recovery manager is not been able to flush all pending work before terminating. This quickstart uses Spring Boot Narayana recovery controller.
7.2.1. Spring Boot Narayana Recovery Controller
The Spring Boot Narayana recovery controller allows to gracefully handle the scaling down phase of a StatefulSet by cleaning pending transactions before termination. If a scaling down operation is executed and the pod is not clean after termination, the previous number of replicas is restored, hence effectively canceling the scaling down operation.
All pods of the StatefulSet require access to a shared volume that is used to store the termination status of each pod belonging to the StatefulSet. The pod-0 of the StatefulSet periodically checks the status and scale the StatefulSet to the right size if there’s a mismatch.
In order for the recovery controller to work, edit permissions on the current namespace are required (role binding is included in the set of resources published to OpenShift). The recovery controller can be disabled using the CLUSTER_RECOVERY_ENABLED
environment variable. In this case, no special permissions are required on the service account but any scale down operation may leave pending transactions on the terminated pod without notice.
7.2.2. Configuring Spring Boot Narayana Recovery Controller
Following example shows how to configure Narayana to work on OpenShift with the recovery controller. This is a sample application.properties
file:
You need to replace the following options in the Kubernetes yaml descriptor, see below TX manager Narayana recovery settings You must enable resource filtering in order to inject the Maven artifactId
# You need to replace the following options in the Kubernetes yaml descriptor, see below
cluster.nodename=1
cluster.base-dir=./target/tx
# TX manager
spring.jta.transaction-manager-id=${cluster.nodename}
spring.jta.log-dir=${cluster.base-dir}/store/${cluster.nodename}
# Narayana recovery settings
snowdrop.narayana.openshift.recovery.enabled=true
snowdrop.narayana.openshift.recovery.current-pod-name=${cluster.nodename}
# You must enable resource filtering in order to inject the Maven artifactId
snowdrop.narayana.openshift.recovery.statefulset=${project.artifactId}
snowdrop.narayana.openshift.recovery.status-dir=${cluster.base-dir}/status
You need a shared volume to store both transactions and information related to termination. It can be mounted in the StatefulSet yaml descriptor:
apiVersion: apps/v1beta1 kind: StatefulSet #... spec: #... template: #... spec: containers: - env: - name: CLUSTER_BASE_DIR value: /var/transaction/data # Override CLUSTER_NODENAME with Kubernetes Downward API (to use `pod-0`, `pod-1` etc. as tx manager id) - name: CLUSTER_NODENAME valueFrom: fieldRef: apiVersion: v1 fieldPath: metadata.name #... volumeMounts: - mountPath: /var/transaction/data name: the-name-of-the-shared-volume #...
apiVersion: apps/v1beta1
kind: StatefulSet
#...
spec:
#...
template:
#...
spec:
containers:
- env:
- name: CLUSTER_BASE_DIR
value: /var/transaction/data
# Override CLUSTER_NODENAME with Kubernetes Downward API (to use `pod-0`, `pod-1` etc. as tx manager id)
- name: CLUSTER_NODENAME
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.name
#...
volumeMounts:
- mountPath: /var/transaction/data
name: the-name-of-the-shared-volume
#...
7.2.3. Camel Extension for Spring Boot Narayana Recovery Controller
If Camel is found in the Spring Boot application context, the Camel context is automatically stopped before flushing all pending transactions.
7.3. Running the Quickstart on OpenShift:
To run the quickstart on a running single node OpenShift cluster:
Download Camel Spring Boot XA project:
Copy to Clipboard Copied! Toggle word wrap Toggle overflow git clone https://github.com/jboss-fuse/spring-boot-camel-xa
git clone https://github.com/jboss-fuse/spring-boot-camel-xa
Navigate to
spring-boot-camel-xa
directory and run following command:Copy to Clipboard Copied! Toggle word wrap Toggle overflow mvn clean install
mvn clean install
Log in to the OpenShift Server as follows:
Copy to Clipboard Copied! Toggle word wrap Toggle overflow oc login -u developer -p developer
oc login -u developer -p developer
Create a new project namespace called
test
(assuming it does not already exist), as follows:Copy to Clipboard Copied! Toggle word wrap Toggle overflow oc new-project test
oc new-project test
If the
test
project namespace already exists, you can switch to it using the following command:Copy to Clipboard Copied! Toggle word wrap Toggle overflow oc project test
oc project test
Install dependencies:
-
From the OpenShift catalog, install
postgresql
using username astheuser
and password asThepassword1!
. -
From the OpenShift catalog, install the
A-MQ
broker using username astheuser
and password asThepassword1!
.
-
From the OpenShift catalog, install
Change the
Postgresql
database to accept prepared statements:Copy to Clipboard Copied! Toggle word wrap Toggle overflow oc env dc/postgresql POSTGRESQL_MAX_PREPARED_TRANSACTIONS=100
oc env dc/postgresql POSTGRESQL_MAX_PREPARED_TRANSACTIONS=100
Create a persistent volume claim for the transaction log:
Copy to Clipboard Copied! Toggle word wrap Toggle overflow oc create -f persistent-volume-claim.yml
oc create -f persistent-volume-claim.yml
Build and deploy your quickstart:
Copy to Clipboard Copied! Toggle word wrap Toggle overflow mvn fabric8:deploy -P openshift
mvn fabric8:deploy -P openshift
Scale it up to the desired number of replicas:
Copy to Clipboard Copied! Toggle word wrap Toggle overflow oc scale statefulset spring-boot-camel-xa --replicas 3
oc scale statefulset spring-boot-camel-xa --replicas 3
Note: The pod name is used as transaction manager id (spring.jta.transaction-manager-id property). The current implementation also limits the length of transaction manager ids. So please note that:
- The name of the StatefulSet is an identifier for the transaction system, so it must not be changed.
- You should name the StatefulSet so that all of its pod names have length lower than or equal to 23 characters. Pod names are created by OpenShift using the convention: <statefulset-name>-0, <statefulset-name>-1 and so on. Narayana does its best to avoid having multiple recovery managers with the same id, so when the pod name is longer than the limit, the last 23 bytes are taken as transaction manager id (after stripping some characters like -).
Once the quickstart is running you can get the base service URL using the following command:
Copy to Clipboard Copied! Toggle word wrap Toggle overflow NARAYANA_HOST=$(oc get route spring-boot-camel-xa -o jsonpath={.spec.host})
NARAYANA_HOST=$(oc get route spring-boot-camel-xa -o jsonpath={.spec.host})
7.4. Testing Successful and Failed XA Transactions
Following workflow shows how to test the successful and failed XA transactions:
Get the list of messages in the audit_log table:
Copy to Clipboard Copied! Toggle word wrap Toggle overflow curl -w "\n" http://$NARAYANA_HOST/api/
curl -w "\n" http://$NARAYANA_HOST/api/
The list is empty at the beginning. Now you can put the first element.
Copy to Clipboard Copied! Toggle word wrap Toggle overflow curl -w "\n" -X POST http://$NARAYANA_HOST/api/?entry=hello
curl -w "\n" -X POST http://$NARAYANA_HOST/api/?entry=hello
After waiting for some time get the new list:
Copy to Clipboard Copied! Toggle word wrap Toggle overflow curl -w "\n" http://$NARAYANA_HOST/api/
curl -w "\n" http://$NARAYANA_HOST/api/
-
The new list contains two messages,
hello
andhello-ok
. Thehello-ok
confirms that the message has been sent to a outgoing queue and then logged. You can add multiple messages and see the logs.
7.4.1. Exception handling
Following workflow shows how to test the failed XA transactions:
Send a message named
fail
:Copy to Clipboard Copied! Toggle word wrap Toggle overflow curl -w "\n" -X POST http://$NARAYANA_HOST/api/?entry=fail
curl -w "\n" -X POST http://$NARAYANA_HOST/api/?entry=fail
After waiting for some time get the new list:
Copy to Clipboard Copied! Toggle word wrap Toggle overflow curl -w "\n" http://$NARAYANA_HOST/api/
curl -w "\n" http://$NARAYANA_HOST/api/
- This message produces an exception at the end of the route, so that the transaction is always rolled back. You should not find any trace of the message in the audit_log table.