You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A **ChangeUnit** is the atomic, versioned unit of change in Flamingock. It encapsulates logic to modify an external system (the [**target system**](../overview/audit-store-vs-target-system.md)) and provides metadata and rollback capability. ChangeUnits are discovered and executed in a defined order to ensure deterministic, auditable changes.
9
-
10
-
### What a changeUnit Is
11
-
-**Self-contained change**
12
-
Each ChangeUnit includes:
13
-
- A unique `id` (unique across the entire application)
14
-
- An `order` determining execution sequence
15
-
- An optional `author` and `description`
16
-
- An `@Execution` method (or template) with the change logic
17
-
- A `@RollbackExecution` method (or template) with compensating logic
18
-
- A `transactional` flag (default `true`) indicating if Flamingock will attempt to wrap execution and audit in a single transaction
19
-
20
-
-**Versioned and Auditable**
21
-
ChangeUnits live in your source code or resources, and their execution is recorded in the [**audit store**](../overview/audit-store-vs-target-system.md) to:
22
-
- Prevent duplicate executions
23
-
- Track history (who ran which change and when)
24
-
- Drive rollbacks and “undo” operations
25
-
26
-
### What a changeUnit is not
27
-
-**Not a long-running job**
28
-
ChangeUnits should complete promptly. Flamingock needs to know the result (success or failure) before proceeding. Long-running or asynchronous operations can lead to unexpected behavior or retries.
29
-
-**Not a general-purpose script**
30
-
While ChangeUnits run code, they are not intended for arbitrary scripting. Their role is to apply deterministic, idempotent changes that evolve your target systems in sync with your application.
6
+
# ChangeUnits Deep Dive
31
7
32
-
---
8
+
## 1. Introduction: Understanding ChangeUnits
33
9
34
-
## ChangeUnit properties
10
+
A **ChangeUnit** is the atomic, versioned, self-contained unit of change in Flamingock.
11
+
It encapsulates logic to evolve [**target systems**](../overview/audit-store-vs-target-system.md) safely, deterministically, and with complete auditability.
35
12
36
-
Every ChangeUnit must define:
37
-
-`id` (String): Unique across all ChangeUnits in the application.
38
-
-`order` (String or numeric): Defines execution order (evaluated lexicographically or numerically).
39
-
-`author` (String): Who is responsible for the change.
40
-
-`description` (String, optional): Brief explanation of the change.
41
-
-`transactional` (boolean, default `true`): Whether Flamingock will attempt to wrap the change and audit insert in one transaction (if the target system and audit store support transactions).
13
+
**Key characteristics:**
14
+
- Executed in sequence based on their `order`
15
+
- Recorded in the audit store to prevent duplicate execution
16
+
- Safe by default: if Flamingock is uncertain about a change's outcome, it stops and requires manual intervention
17
+
- Each ChangeUnit runs exactly once per system
42
18
43
19
---
44
20
45
-
## Types of changeUnits
21
+
## 2. Structure of a ChangeUnit
22
+
23
+
### Required Properties
24
+
-**`id`**: Unique identifier across all ChangeUnits in the application
25
+
-**`order`**: Execution sequence (must use zero-padded format like `0001`, `0002`, `_0001_ChangeName`)
26
+
-**`author`**: Who is responsible for this change
27
+
28
+
### Optional Properties
29
+
-**`description`**: Brief explanation of what the change does
30
+
-**`transactional`** (default `true`): Only relevant if the target system supports transactions. Has no effect on non-transactional systems like S3 or Kafka.
31
+
32
+
### Required Annotations and Methods
33
+
-**`@TargetSystem`**: Specifies which system this change affects
34
+
-**`@ChangeUnit`**: Marks the class as a ChangeUnit
35
+
-**`@Execution`**: The method containing your change logic
36
+
-**`@RollbackExecution`**: The method to undo the change (required for safety and governance)
37
+
38
+
> **Note:** Rollback is important because in **non-transactional systems**, it's be used to revert changes if execution fails. In **all systems**, rollback is essential for undo operations (via CLI or UI).
46
39
47
-
ChangeUnits can be defined based on two approaches: code-based and [template-based](../templates/templates-introduction.md)
40
+
## 3. Types of ChangeUnits
48
41
49
-
### Code-based changeUnits
50
-
Code-based ChangeUnits are written in Java (or Kotlin/Groovy) with annotations:
42
+
### Code-based ChangeUnits
43
+
Written in Java (or Kotlin/Groovy) with annotations. Best for **specific jobs** or when you need a **flexibility window** that isn’t covered by an existing template.
44
+
45
+
This approach gives you full programmatic control, making it the fallback option when no reusable template exists for your use case.
-**Location**: Files must reside in a source package scanned by Flamingock (default: `src/main/java`).
75
-
-**Naming**: Class names should match `_ORDER_name` (e.g., `_0001_CreateS3BucketChange`) to simplify ordering and visibility.
76
-
-**Dependencies**: Flamingock injects dependencies (e.g., `S3Client`, `MongoClient`) via Spring or builder-based DI.
68
+
### Template-based ChangeUnits
69
+
Template-based ChangeUnits use YAML or JSON definitions. They are especially useful for **repetitive or parameterized operations**, where the same logic can to be applied multiple times with different configurations.
70
+
71
+
- The execution logic is encapsulated in a **template** (provided by Flamingock, a contributor, or created by you).
72
+
- Each ChangeUnit then supplies its own configuration to apply that logic consistently.
73
+
- This approach ensures **immutability** (the YAML/JSON file itself represents the change) and makes it easier to **reuse proven patterns**.
77
74
78
-
### Template-based changeUnits
79
-
Template-based ChangeUnits use YAML or JSON definitions. Example (SQL DDL):
80
75
81
76
```yaml
82
-
#/src/main/resources/_0003_add_status_column.yml
77
+
#File: _0002_add_status_column.yml
83
78
id: add_status_column
84
-
order: 0003
79
+
order: "0002"
85
80
author: "db-team"
86
-
description: "Add 'status' column to 'orders' table"
81
+
description: "Add status column to orders table"
87
82
templateName: sql-template
88
83
templateConfiguration:
89
84
executionSql: |
90
-
ALTER TABLE orders ADD COLUMN status VARCHAR(20);
85
+
ALTER TABLE orders ADD COLUMN status VARCHAR(20) DEFAULT 'pending';
91
86
rollbackSql: |
92
87
ALTER TABLE orders DROP COLUMN status;
93
88
```
94
89
95
-
#### Discoverability & execution
96
-
- **Location**: While Flamingock will scan src/main/resources by default, we **strongly recommend** placing template files in the same code‐package/directory as your code‐based ChangeUnits.
97
-
- This ensures that both code‐based and template‐based ChangeUnits live side by side for visibility and immutability.
98
-
- **Naming**: File names should follow `_ORDER_name.yml` or `_ORDER_name.json`.
99
-
- **Advantages**:
100
-
- Easier immutability: The YAML/JSON file itself represents the change, avoiding modifications in code.
101
-
- Better for simple, repeatable tasks (e.g., SQL DDL).
90
+
Both types follow the same execution model and provide the same safety guarantees.
102
91
103
-
---
104
-
105
-
[//]: # (## How ChangeUnits Are Discovered & Executed)
92
+
## 4. Naming & Discoverability
106
93
107
-
[//]: # ()
108
-
[//]: # (Flamingock uses **classpath scanning** to locate ChangeUnits:)
94
+
### Enforced Naming Convention
95
+
All ChangeUnit files (both code and templates) **must** follow this pattern:
109
96
110
-
[//]: # ()
111
-
[//]: # (- **Code-based**: Scans specified packages for classes annotated with `@ChangeUnit` or `@Change`.)
97
+
- **Format**: `_XXXX_DescriptiveName`
98
+
- **Order**: Must be at least 4 digits, zero-padded (e.g., `0001`, `0002`, `0100`)
- **Deterministic ordering**: Ensures consistent execution across environments
114
107
115
-
[//]: # ()
116
-
[//]: # (Flamingock builds a **pipeline** of stages and executes ChangeUnits in ascending order based on `order`.)
108
+
### File Locations
109
+
- **Code-based**: Place in packages scanned by Flamingock (default: `src/main/java`)
110
+
- **Template-based**: Place in `src/main/resources` or preferably alongside code-based ChangeUnits
111
+
- **Recommendation**: Keep all ChangeUnits (code and templates) in the same package/directory for better organization
117
112
118
-
[//]: # ()
119
-
[//]: # (---)
113
+
## 5. Transactional Behavior
120
114
121
-
## Considerations
115
+
- **Transactional target systems** (e.g., MongoDB, PostgreSQL): operations run within a transaction **unless you explicitly set `transactional = false`**.
116
+
- **Non-transactional target systems** (e.g., S3, Kafka): the `transactional` flag has no effect — operations are applied without transactional guarantees.
122
117
123
-
### Transactional behavior
124
-
- **Transactional changes (default)**: When the target system and audit store share a transactional context (e.g., MongoDB CE), Flamingock wraps both in a single transaction.
125
-
- **Non-transactional changes**: `transactional = false`. Flamingock executes `@Execution` and, upon success, writes to the audit store. If `@Execution` fails, Flamingock invokes `@RollbackExecution`. See [transactions page](../flamingock-library-config/transactions.md)
126
-
118
+
Some operations may require setting `transactional = false` even in databases:
119
+
- DDL operations (e.g., CREATE INDEX, ALTER TABLE)
120
+
- Large bulk operations that exceed transaction limits
- **Code-based**: Once committed and possibly executed, avoid modifying the class. Instead, introduce a new ChangeUnit for evolution.
130
-
- **Template-based**: Treat the file as immutable. Modifying an existing template breaks history ordering — use new template files for new changes.
123
+
➡️ To understand how to define and configure **target systems**, see [Target System Configuration](../overview/audit-store-vs-target-system.md)
131
124
132
-
### Audit store constraints
133
-
- **Single audit store per application**: All ChangeUnits in one application write to the same audit store.
134
-
- **Audit store integrity**: Do not manually modify audit records in the audit store; this can corrupt Flamingock’s state. Use CLI/UI for supported modifications.
125
+
## 6. Default Safety & Recovery
135
126
136
-
### Idempotency
137
-
- ChangeUnits should be idempotent or safe to re-run. Flamingock retries failed ChangeUnits on next startup. If a non-transactional ChangeUnit partially succeeded, ensure it can handle multiple executions or include appropriate guards.
138
-
139
-
---
127
+
**Flamingock's core principle**: If a ChangeUnit execution result is uncertain, Flamingock stops and requires manual intervention. This prevents silent data corruption.
140
128
141
-
## Best practices
129
+
**What this means:**
130
+
- If a change fails, Flamingock halts execution
131
+
- The issue is recorded in the audit store
132
+
- Manual investigation and resolution is required via CLI (or Cloud UI in Cloud Edition)
142
133
143
-
**Name and location conventions***
144
-
- Place both code-based and template-based ChangeUnits in the same source package/directory for visibility and immutability.
145
-
- Use filenames or class names prefixed with the zero-padded order (e.g., `_0001_create_s3_bucket.java` or `_0001_create_s3_bucket.yaml`).
134
+
➡️ **For advanced recovery strategies**, see [Recovery Strategies](../recovery-and-safety/recovery-strategies.md)
146
135
147
-
- **Always provide rollback**
148
-
Even for transactional ChangeUnits, implement `@RollbackExecution` so CLI “undo” operations work smoothly.
136
+
## 7. Best Practices
149
137
150
-
- **Template-based changeUnits for simplicity and immutability**
151
-
Favor templated ChangeUnits (YAML/JSON) for routine, repeatable tasks—such as SQL DDL, configuration toggles, or small API calls. Templates are inherently immutable (being a static file), making it easier to adhere to versioning best practices.
138
+
### Core Principles
139
+
- **Treat ChangeUnits as immutable**: Once deployed, never modify existing ChangeUnits. Create new ones for corrections.
140
+
- **Always provide @RollbackExecution**: Important for CLI undo operations and recovery scenarios.
141
+
- **Keep scope focused**: One ChangeUnit should address one logical change.
152
142
153
-
- **Use Flamingock’s batching feature for long-running operations**(coming soon)
154
-
For ChangeUnits that process large workloads (e.g., migrating millions of rows), leverage Flamingock’s built-in batching mechanism. Define a single ChangeUnit that iterates through data in batches; Flamingock will mark it as complete only when all batches succeed, and will resume from the last processed batch on retry.
143
+
### Technical Guidelines
144
+
- **Make operations idempotent when possible**: Try to design changes that can be safely re-run.
145
+
- **Test both execution and rollback**: Include ChangeUnit testing in your CI/CD pipeline.
146
+
- **Follow naming conventions**: Use the `_XXXX_DescriptiveName` pattern consistently.
155
147
156
-
- **Inject minimal dependencies**
157
-
Only inject what you need (e.g., clients, DAOs). Avoid injecting large application contexts within ChangeUnits.
148
+
### Organizational Best Practices
149
+
- **Clear authorship**: Always specify the `author` for accountability.
150
+
- **Version control discipline**: Review ChangeUnits in pull requests like any critical code.
151
+
- **Document complex changes**: Use the `description` field to explain non-obvious logic.
152
+
- **Maintain change logs**: Keep a high-level record of what changes were made when.
158
153
159
-
- **Write clear descriptions**
160
-
Use the `description` property to explain the purpose and impact of each ChangeUnit.
161
154
162
-
- **Implement idempotency**
163
-
For non-transactional operations (e.g., deleting an S3 bucket), wrap calls in checks (e.g., “if exists”) to handle re-runs gracefully.
164
-
165
-
- **Immutable operations**
166
-
Once a ChangeUnit is applied to any environment, treat its code or template as immutable. For corrections, create new ChangeUnits rather than editing old ones.
167
-
168
-
- **Explicit ordering**
169
-
Declare a clear, numeric `order` for each ChangeUnit. Relying on implicit or alphabetical ordering can introduce hidden dependencies and make debugging deployment issues difficult.
170
-
171
-
- **Audit store hygiene**
172
-
Never manually edit or delete records in the audit store. Direct modifications can corrupt Flamingock’s internal state and lead to unpredictable behavior or data loss. If you need to correct audit data, use Flamingock’s supported operations (CLI or UI) or follow documented recovery procedures.
155
+
---
173
156
174
-
- **Documentation and metadata**
175
-
Use the `author` and `description` (if available) fields to document the intent of each ChangeUnit. This metadata helps teams understand why a change was made and by whom—critical for code reviews and compliance audits.
157
+
**Next Steps:**
158
+
- Learn about [dependency injection](./changeunit-dependency-injection.md) in ChangeUnits
159
+
- Explore [template-based ChangeUnits](../templates/templates-introduction.md) for declarative changes
160
+
- Understand [advanced recovery strategies](../recovery-and-safety/recovery-strategies.md) for production scenarios
0 commit comments