From 2ef1bed39a55313a2c658170c29cfc8af296907a Mon Sep 17 00:00:00 2001 From: Stephan Pelikan Date: Mon, 9 Sep 2024 15:25:09 +0200 Subject: [PATCH] Avoid optimistic locking exceptions in clusters (#58) --- spring-boot/pom.xml | 5 ++ .../Camunda8AdapterConfiguration.java | 2 + .../deployment/Camunda8DeploymentAdapter.java | 13 ++--- .../deployment/DeploymentService.java | 53 +++++++++++++++++-- .../service/Camunda8ProcessService.java | 2 +- 5 files changed, 61 insertions(+), 14 deletions(-) diff --git a/spring-boot/pom.xml b/spring-boot/pom.xml index 07d9bf9..114d539 100644 --- a/spring-boot/pom.xml +++ b/spring-boot/pom.xml @@ -47,6 +47,11 @@ spring-tx 6.1.3 + + org.springframework.retry + spring-retry + 2.0.8 + org.springframework.boot spring-boot-starter-aop diff --git a/spring-boot/src/main/java/io/vanillabp/camunda8/Camunda8AdapterConfiguration.java b/spring-boot/src/main/java/io/vanillabp/camunda8/Camunda8AdapterConfiguration.java index 9a698d1..1110752 100644 --- a/spring-boot/src/main/java/io/vanillabp/camunda8/Camunda8AdapterConfiguration.java +++ b/spring-boot/src/main/java/io/vanillabp/camunda8/Camunda8AdapterConfiguration.java @@ -38,10 +38,12 @@ import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; import org.springframework.data.repository.CrudRepository; +import org.springframework.retry.annotation.EnableRetry; @AutoConfigurationPackage(basePackageClasses = Camunda8AdapterConfiguration.class) @AutoConfigureBefore(CamundaAutoConfiguration.class) @EnableConfigurationProperties(Camunda8VanillaBpProperties.class) +@EnableRetry public class Camunda8AdapterConfiguration extends AdapterConfigurationBase> { private static final Logger logger = LoggerFactory.getLogger(Camunda8AdapterConfiguration.class); diff --git a/spring-boot/src/main/java/io/vanillabp/camunda8/deployment/Camunda8DeploymentAdapter.java b/spring-boot/src/main/java/io/vanillabp/camunda8/deployment/Camunda8DeploymentAdapter.java index 1eeec31..560b8ba 100644 --- a/spring-boot/src/main/java/io/vanillabp/camunda8/deployment/Camunda8DeploymentAdapter.java +++ b/spring-boot/src/main/java/io/vanillabp/camunda8/deployment/Camunda8DeploymentAdapter.java @@ -21,13 +21,6 @@ import io.vanillabp.camunda8.wiring.Camunda8TaskWiring; import io.vanillabp.springboot.adapter.ModuleAwareBpmnDeployment; import io.vanillabp.springboot.adapter.VanillaBpProperties; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.context.event.EventListener; -import org.springframework.core.io.Resource; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.util.StreamUtils; - import java.io.ByteArrayInputStream; import java.io.IOException; import java.util.Arrays; @@ -36,8 +29,12 @@ import java.util.Objects; import java.util.stream.Collectors; import java.util.stream.Stream; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.event.EventListener; +import org.springframework.core.io.Resource; +import org.springframework.util.StreamUtils; -@Transactional public class Camunda8DeploymentAdapter extends ModuleAwareBpmnDeployment { private static final Logger logger = LoggerFactory.getLogger(Camunda8DeploymentAdapter.class); diff --git a/spring-boot/src/main/java/io/vanillabp/camunda8/deployment/DeploymentService.java b/spring-boot/src/main/java/io/vanillabp/camunda8/deployment/DeploymentService.java index a8c8934..991ebe4 100644 --- a/spring-boot/src/main/java/io/vanillabp/camunda8/deployment/DeploymentService.java +++ b/spring-boot/src/main/java/io/vanillabp/camunda8/deployment/DeploymentService.java @@ -3,10 +3,15 @@ import io.camunda.zeebe.client.api.response.Process; import io.camunda.zeebe.model.bpmn.Bpmn; import io.camunda.zeebe.model.bpmn.BpmnModelInstance; - import java.io.ByteArrayOutputStream; import java.time.OffsetDateTime; import java.util.List; +import org.springframework.dao.OptimisticLockingFailureException; +import org.springframework.retry.annotation.Backoff; +import org.springframework.retry.annotation.Recover; +import org.springframework.retry.annotation.Retryable; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; public class DeploymentService { @@ -22,12 +27,17 @@ public DeploymentService( this.deploymentResourceRepository = deploymentResourceRepository; } - + + @Transactional(propagation = Propagation.REQUIRES_NEW) + @Retryable( + retryFor = OptimisticLockingFailureException.class, + maxAttempts = 100, + backoff = @Backoff(delay = 100, maxDelay = 500)) public DeployedBpmn addBpmn( final BpmnModelInstance model, final int fileId, final String resourceName) { - + final var previous = deploymentResourceRepository.findById(fileId); if (previous.isPresent()) { return (DeployedBpmn) previous.get(); @@ -44,12 +54,31 @@ public DeployedBpmn addBpmn( return deploymentResourceRepository.save(bpmn); } - + + @Recover + public DeployedBpmn recoverAddBpmn( + final OptimisticLockingFailureException exception, + final BpmnModelInstance model, + final int fileId, + final String resourceName) { + + throw new RuntimeException( + "Could not save BPMN '" + + resourceName + + "' in local DB due to stale OptimisticLockingFailureException", exception); + + } + + @Transactional(propagation = Propagation.REQUIRES_NEW) + @Retryable( + retryFor = OptimisticLockingFailureException.class, + maxAttempts = 100, + backoff = @Backoff(delay = 100, maxDelay = 500)) public DeployedProcess addProcess( final int packageId, final Process camunda8DeployedProcess, final DeployedBpmn bpmn) { - + final var versionedId = camunda8DeployedProcess.getProcessDefinitionKey(); final var previous = deploymentRepository.findByDefinitionKey(versionedId); @@ -71,6 +100,20 @@ public DeployedProcess addProcess( } + @Recover + public DeployedProcess recoverAddProcess( + final OptimisticLockingFailureException exception, + final int packageId, + final Process camunda8DeployedProcess, + final DeployedBpmn bpmn) { + + throw new RuntimeException( + "Could not save Process '" + + camunda8DeployedProcess.getBpmnProcessId() + + "' in local DB due to stale OptimisticLockingFailureException", exception); + + } + public List getBpmnNotOfPackage(final int packageId) { return deploymentResourceRepository diff --git a/spring-boot/src/main/java/io/vanillabp/camunda8/service/Camunda8ProcessService.java b/spring-boot/src/main/java/io/vanillabp/camunda8/service/Camunda8ProcessService.java index c773042..c1829c0 100644 --- a/spring-boot/src/main/java/io/vanillabp/camunda8/service/Camunda8ProcessService.java +++ b/spring-boot/src/main/java/io/vanillabp/camunda8/service/Camunda8ProcessService.java @@ -342,7 +342,7 @@ private DE runInTransaction( Camunda8AdapterConfiguration.ADAPTER_ID, camunda8Properties.getTenantId(parent.getWorkflowModuleId()), parent.getWorkflowModuleId(), - aggregateId == null ? null : aggregateId.toString(), + aggregateId.toString(), bpmnProcessId, taskIdToTestForAlreadyCompletedOrCancelled, null,