|
| 1 | +--- |
| 2 | +title: Idempotency Registry |
| 3 | +--- |
| 4 | + |
| 5 | +The Idempotency Registry is a feature designed to prevent duplicate worker invocations. It ensures that if a task is processed multiple times (e.g., due to network issues or retries in the process engine), the worker logic is only executed once, and the previous result is returned for subsequent calls. |
| 6 | + |
| 7 | +## How it Works |
| 8 | + |
| 9 | +When a worker is triggered, the process engine worker: |
| 10 | +1. Checks the `IdempotencyRegistry` if a result already exists for the given `taskId`. |
| 11 | +2. If a result exists, it skips the worker execution and returns the stored result. |
| 12 | +3. If no result exists, it executes the worker. |
| 13 | +4. After successful execution, it registers the result in the `IdempotencyRegistry`. |
| 14 | + |
| 15 | +## Implementations |
| 16 | + |
| 17 | +There are three available implementations of the `IdempotencyRegistry`: |
| 18 | + |
| 19 | +| Implementation | Description | Recommended Use | |
| 20 | +| --- | --- | --- | |
| 21 | +| `NoOpIdempotencyRegistry` | Does nothing. No results are stored or retrieved. | Default, use if idempotency is handled elsewhere. | |
| 22 | +| `InMemoryIdempotencyRegistry` | Stores results in a local `ConcurrentHashMap`. | Testing or non-clustered environments. | |
| 23 | +| `JpaIdempotencyRegistry` | Stores results in a database using JPA. | Production, clustered environments. | |
| 24 | + |
| 25 | +## Setup Procedures |
| 26 | + |
| 27 | +### In-Memory Registry |
| 28 | + |
| 29 | +To use the in-memory registry, you need to provide a bean of type `IdempotencyRegistry` in your Spring configuration: |
| 30 | + |
| 31 | +```kotlin |
| 32 | +@Configuration |
| 33 | +class IdempotencyConfiguration { |
| 34 | + |
| 35 | + @Bean |
| 36 | + fun idempotencyRegistry(): IdempotencyRegistry = InMemoryIdempotencyRegistry() |
| 37 | + |
| 38 | +} |
| 39 | +``` |
| 40 | + |
| 41 | +> **Warning:** The `InMemoryIdempotencyRegistry` is not suitable for clustered environments as the state is not shared between nodes. |
| 42 | +
|
| 43 | +### JPA-based Registry |
| 44 | + |
| 45 | +The JPA-based registry is suitable for production environments. It persists the results in the database, allowing multiple instances of the worker to share the same idempotency state. |
| 46 | + |
| 47 | +#### 1. Add Dependency |
| 48 | + |
| 49 | +Add the following dependency to your `pom.xml`: |
| 50 | + |
| 51 | +```xml |
| 52 | +<dependency> |
| 53 | + <groupId>dev.bpm-crafters.process-engine-worker</groupId> |
| 54 | + <artifactId>process-engine-worker-spring-boot-idempotency-registry-jpa</artifactId> |
| 55 | + <version>${process-engine-worker.version}</version> |
| 56 | +</dependency> |
| 57 | +``` |
| 58 | + |
| 59 | +The `JpaIdempotencyAutoConfiguration` will automatically register the `JpaIdempotencyRegistry` if an `EntityManager` is present and no other `IdempotencyRegistry` bean is defined. |
| 60 | + |
| 61 | +#### 2. Database Schema (Liquibase) |
| 62 | + |
| 63 | +The JPA registry requires a table named `task_log_entry_`. You can use the following Liquibase changeSet to create it: |
| 64 | + |
| 65 | +```yaml |
| 66 | +databaseChangeLog: |
| 67 | + - changeSet: |
| 68 | + id: create-idempotency-table |
| 69 | + author: bpm-crafters |
| 70 | + changes: |
| 71 | + - createTable: |
| 72 | + tableName: task_log_entry_ |
| 73 | + columns: |
| 74 | + - column: |
| 75 | + name: task_id_ |
| 76 | + type: varchar(100) |
| 77 | + constraints: |
| 78 | + nullable: false |
| 79 | + primaryKey: true |
| 80 | + primaryKeyName: task_log_entry_pk_ |
| 81 | + - column: |
| 82 | + name: process_instance_id_ |
| 83 | + type: varchar(100) |
| 84 | + constraints: |
| 85 | + nullable: false |
| 86 | + - column: |
| 87 | + name: created_at_ |
| 88 | + type: timestamp |
| 89 | + constraints: |
| 90 | + nullable: false |
| 91 | + - column: |
| 92 | + name: result_ |
| 93 | + type: blob # or bytea for PostgreSQL |
| 94 | + constraints: |
| 95 | + nullable: false |
| 96 | +``` |
| 97 | +
|
| 98 | +> **Note:** The `result_` column type should be suitable for storing binary data (e.g., `blob` for most databases, `bytea` for PostgreSQL). |
0 commit comments