Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/tx handling #55

Merged
merged 15 commits into from
Jul 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<artifactId>camunda8-adapter</artifactId>

<name>VanillaBP SPI adapter for Camunda 8.x</name>
<version>1.3.1-SNAPSHOT</version>
<version>1.4.0-SNAPSHOT</version>
<packaging>pom</packaging>

<properties>
Expand Down
40 changes: 38 additions & 2 deletions spring-boot/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -190,15 +190,51 @@ Since Camunda 8 is an external system to your services one has to deal with even
1. Camunda 8 is not reachable / cannot process the confirmation of a completed task
1. The task to be completed was cancelled meanwhile e.g. due to boundary events

If there is an exception in your business code and you have to roll back the transaction then Camunda's task retry-mechanism should retry as configured. Additionally, the `TaskException` is used for expected business errors handled by BPMN error boundary events which must not cause a rollback. To achieve both one should mark the service bean like this:
In order to activate this behavior one has to mark methods accessing VanillaBP-APIs as `@Transactional`, either by
using the method-level annotation:

```java
@Service
@WorkflowService(workflowAggregateClass = Ride.class)
@Transactional(noRollbackFor = TaskException.class)
public class TaxiRide {
@Autowired
private ProcessService<Ride> processService;

@Transactional
public void receivePayment(...) {
...
processService.startWorkflow(ride);
...
}

@Transactional
@WorkflowTask
public void chargeCreditCard(final Ride ride) {
...
}

@Transactional
public void paymentReceived(final Ride ride) {
...
processService.correlateMessage(ride, 'PaymentReceived');
...
}
}
```

or the class-level annotation:

```java
@Service
@WorkflowService(workflowAggregateClass = Ride.class)
@Transactional
public class TaxiRide {
...
}
```

If there is an exception in your business code and you have to roll back the transaction then Camunda's task retry-mechanism should retry as configured. Additionally, the `TaskException` is used for expected business errors handled by BPMN error boundary events which must not cause a rollback. This is handled by the adapter, one does not need to take care about it.

## Workflow aggregate serialization

On using C7 one can use workflow aggregates having relations and calculated values:
Expand Down
15 changes: 10 additions & 5 deletions spring-boot/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@
<parent>
<groupId>org.camunda.community.vanillabp</groupId>
<artifactId>camunda8-adapter</artifactId>
<version>1.3.1-SNAPSHOT</version>
<version>1.4.0-SNAPSHOT</version>
</parent>

<artifactId>camunda8-spring-boot-adapter</artifactId>
<name>VanillaBP SPI adapter for Camunda 8.x for Spring Boot</name>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.zeebe.version>8.3.4.2</spring.zeebe.version>
<spring.zeebe.version>8.5.4</spring.zeebe.version>
</properties>

<build>
Expand All @@ -38,14 +38,19 @@
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>io.camunda</groupId>
<artifactId>spring-zeebe-starter</artifactId>
<groupId>io.camunda.spring</groupId>
<artifactId>spring-boot-starter-camunda</artifactId>
<version>${spring.zeebe.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.3.23</version>
<version>6.1.3</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
<version>3.2.5</version><!-- see pom of spring-client-root -->
</dependency>
<dependency>
<groupId>jakarta.persistence</groupId>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
package io.vanillabp.camunda8;

import io.camunda.zeebe.spring.client.CamundaAutoConfiguration;
import io.camunda.zeebe.spring.client.jobhandling.DefaultCommandExceptionHandlingStrategy;
import io.vanillabp.camunda8.deployment.Camunda8DeploymentAdapter;
import io.vanillabp.camunda8.deployment.DeploymentRepository;
import io.vanillabp.camunda8.deployment.DeploymentResourceRepository;
import io.vanillabp.camunda8.deployment.DeploymentService;
import io.vanillabp.camunda8.service.Camunda8ProcessService;
import io.vanillabp.camunda8.service.Camunda8TransactionAspect;
import io.vanillabp.camunda8.service.Camunda8TransactionProcessor;
import io.vanillabp.camunda8.wiring.Camunda8Connectable.Type;
import io.vanillabp.camunda8.wiring.Camunda8TaskHandler;
import io.vanillabp.camunda8.wiring.Camunda8TaskWiring;
Expand All @@ -17,6 +18,8 @@
import io.vanillabp.springboot.adapter.VanillaBpProperties;
import io.vanillabp.springboot.parameters.MethodParameter;
import jakarta.annotation.PostConstruct;
import java.lang.reflect.Method;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.framework.AopProxyUtils;
Expand All @@ -29,13 +32,13 @@
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Scope;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.data.repository.CrudRepository;

import java.lang.reflect.Method;
import java.util.List;

@AutoConfigurationPackage(basePackageClasses = Camunda8AdapterConfiguration.class)
@AutoConfigureBefore(CamundaAutoConfiguration.class)
@EnableConfigurationProperties(Camunda8VanillaBpProperties.class)
Expand All @@ -57,9 +60,6 @@ public class Camunda8AdapterConfiguration extends AdapterConfigurationBase<Camun
@Autowired
private ApplicationContext applicationContext;

@Autowired
private DefaultCommandExceptionHandlingStrategy commandExceptionHandlingStrategy;

@Autowired
private DeploymentRepository deploymentRepository;

Expand All @@ -69,6 +69,9 @@ public class Camunda8AdapterConfiguration extends AdapterConfigurationBase<Camun
@Autowired
private Camunda8VanillaBpProperties camunda8Properties;

@Autowired
private ApplicationEventPublisher eventPublisher;

@PostConstruct
public void init() {

Expand All @@ -77,6 +80,14 @@ public void init() {

}

@Bean
@Order(Ordered.LOWEST_PRECEDENCE)
public Camunda8TransactionAspect camunda8TransactionAspect() {

return new Camunda8TransactionAspect(eventPublisher);

}

@Override
public String getAdapterId() {

Expand Down Expand Up @@ -148,7 +159,6 @@ public Camunda8TaskHandler camunda8TaskHandler(

return new Camunda8TaskHandler(
taskType,
commandExceptionHandlingStrategy,
repository,
bean,
method,
Expand All @@ -166,8 +176,9 @@ public <DE> Camunda8ProcessService<?> newProcessServiceImplementation(

final var result = new Camunda8ProcessService<DE>(
camunda8Properties,
eventPublisher,
workflowAggregateRepository,
workflowAggregate -> springDataUtil.getId(workflowAggregate),
springDataUtil::getId,
workflowAggregateClass);

putConnectableService(workflowAggregateClass, result);
Expand All @@ -185,4 +196,31 @@ public SpringBeanUtil vanillabpSpringBeanUtil(

}

/*
* https://www.tirasa.net/en/blog/dynamic-spring-s-transactional-2020-edition
*/
/*
@Bean
public static BeanFactoryPostProcessor camunda8TransactionInterceptorInjector() {

return beanFactory -> {
String[] names = beanFactory.getBeanNamesForType(TransactionInterceptor.class);
for (String name : names) {
BeanDefinition bd = beanFactory.getBeanDefinition(name);
bd.setBeanClassName(Camunda8TransactionInterceptor.class.getName());
bd.setFactoryBeanName(null);
bd.setFactoryMethodName(null);
}
};

}
*/

@Bean
public Camunda8TransactionProcessor camunda8TransactionProcessor() {

return new Camunda8TransactionProcessor();

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ public String getTenantId(
if (!configuration.isUseTenants()) {
return null;
}
if (StringUtils.hasText(configuration.getTenant())) {
return configuration.getTenant();
if (StringUtils.hasText(configuration.getTenantId())) {
return configuration.getTenantId();
}
return workflowModuleId;

Expand Down Expand Up @@ -101,7 +101,7 @@ public static class AdapterConfiguration extends WorkerProperties {

private boolean useTenants = true;

private String tenant;
private String tenantId;

public boolean isUseTenants() {
return useTenants;
Expand All @@ -111,12 +111,12 @@ public void setUseTenants(boolean useTenants) {
this.useTenants = useTenants;
}

public String getTenant() {
return tenant;
public String getTenantId() {
return tenantId;
}

public void setTenant(String tenant) {
this.tenant = tenant;
public void setTenantId(String tenantId) {
this.tenantId = tenantId;
}

}
Expand Down
Loading