@sfdxy/mule-lint 1.21.0 → 1.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/package.json +1 -1
- package/dist/src/mcp/prompts/index.d.ts +1 -1
- package/dist/src/mcp/prompts/index.d.ts.map +1 -1
- package/dist/src/mcp/prompts/index.js +62 -1
- package/dist/src/mcp/prompts/index.js.map +1 -1
- package/dist/src/mcp/resources/index.js +114 -16
- package/dist/src/mcp/resources/index.js.map +1 -1
- package/dist/src/mcp/tools/getRuleDetails.d.ts.map +1 -1
- package/dist/src/mcp/tools/getRuleDetails.js +30 -1
- package/dist/src/mcp/tools/getRuleDetails.js.map +1 -1
- package/docs/README.md +87 -27
- package/docs/best-practices/ci-cd.md +135 -0
- package/docs/best-practices/connector-patterns.md +253 -0
- package/docs/best-practices/dataweave-patterns.md +370 -0
- package/docs/best-practices/deployment-2026.md +171 -0
- package/docs/best-practices/error-handling.md +277 -0
- package/docs/best-practices/event-driven-patterns.md +424 -0
- package/docs/best-practices/logging.md +163 -0
- package/docs/best-practices/mulesoft-best-practices.md +72 -865
- package/docs/best-practices/performance.md +273 -0
- package/docs/best-practices/security.md +181 -0
- package/docs/best-practices/testing.md +190 -0
- package/docs/best-practices/variable-contracts.md +191 -0
- package/package.json +1 -1
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
# DataWeave Best Practices
|
|
2
|
+
|
|
3
|
+
> **Applies to:** All
|
|
4
|
+
> **Related Rules:** `DW-001` · `DW-002` · `DW-003` · `DW-004` · `DW-005`
|
|
5
|
+
> **Last Updated:** April 2026
|
|
6
|
+
|
|
7
|
+
## When to Read This
|
|
8
|
+
|
|
9
|
+
Read this when writing DataWeave transformations, creating reusable DWL modules, or debugging type coercion issues with connectors.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Key Principles
|
|
14
|
+
|
|
15
|
+
1. **Externalize complex transforms** — inline DWL > 5 lines should be in a `.dwl` file
|
|
16
|
+
2. **Create reusable modules** — shared logic goes in `dwl/modules/`
|
|
17
|
+
3. **Use full import paths** — `import X from dwl::modules::Y` (short paths fail at runtime)
|
|
18
|
+
4. **Match connector type expectations** — SF connector needs Java types, not strings
|
|
19
|
+
5. **Use kebab-case for file names** — `transform-order.dwl`, not `transformOrder.dwl`
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Project Structure
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
src/main/resources/dwl/
|
|
27
|
+
├── modules/ # Reusable DWL modules
|
|
28
|
+
│ ├── salesforceUtility.dwl # Type coercion for SF connector
|
|
29
|
+
│ ├── oauth1Header.dwl # OAuth 1.0 HMAC-SHA256 header generator
|
|
30
|
+
│ └── dateUtils.dwl # Shared date formatting functions
|
|
31
|
+
├── transforms/ # Entity-specific transforms
|
|
32
|
+
│ ├── sf-account-to-ns-customer.dwl
|
|
33
|
+
│ ├── salesforce-upsert-response.dwl
|
|
34
|
+
│ ├── error-payload.dwl
|
|
35
|
+
│ └── ...
|
|
36
|
+
├── lookups/ # Enum mapping modules
|
|
37
|
+
│ ├── countryMap.dwl # ISO country → target system enum
|
|
38
|
+
│ └── currencyMap.dwl # ISO currency → target system ID
|
|
39
|
+
└── dictionaries/ # Environment-specific lookup data
|
|
40
|
+
├── customer-segment-dictionary-dev.json
|
|
41
|
+
└── customer-segment-dictionary-prod.json
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Patterns
|
|
47
|
+
|
|
48
|
+
### Pattern 1: External DWL Transform Files
|
|
49
|
+
|
|
50
|
+
**Use when:** any transform exceeds 5 lines of DataWeave.
|
|
51
|
+
|
|
52
|
+
```xml
|
|
53
|
+
<!-- ❌ Bad — large inline transform -->
|
|
54
|
+
<ee:transform>
|
|
55
|
+
<ee:set-payload><![CDATA[%dw 2.0
|
|
56
|
+
<!-- 50+ lines of DataWeave -->
|
|
57
|
+
]]></ee:set-payload>
|
|
58
|
+
</ee:transform>
|
|
59
|
+
|
|
60
|
+
<!-- ✅ Good — external file reference -->
|
|
61
|
+
<ee:transform doc:name="SF Account → NS Customer">
|
|
62
|
+
<ee:message>
|
|
63
|
+
<ee:set-payload resource="dwl/transforms/sf-account-to-ns-customer.dwl"/>
|
|
64
|
+
</ee:message>
|
|
65
|
+
</ee:transform>
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Pattern 2: Reusable DWL Modules
|
|
69
|
+
|
|
70
|
+
**Use when:** logic is shared across multiple transforms (date formatting, type coercion, enum lookups).
|
|
71
|
+
|
|
72
|
+
```dataweave
|
|
73
|
+
// dwl/modules/dateUtils.dwl
|
|
74
|
+
%dw 2.0
|
|
75
|
+
|
|
76
|
+
fun formatDate(date: DateTime) =
|
|
77
|
+
date as String {format: "yyyy-MM-dd"}
|
|
78
|
+
|
|
79
|
+
fun formatDateTime(date: DateTime) =
|
|
80
|
+
date as String {format: "yyyy-MM-dd'T'HH:mm:ss.SSSZ"}
|
|
81
|
+
|
|
82
|
+
fun maskPII(value: String) =
|
|
83
|
+
value[0 to 2] ++ "****" ++ value[-2 to -1]
|
|
84
|
+
|
|
85
|
+
fun toErrorResponse(error, correlationId: String) = {
|
|
86
|
+
correlationId: correlationId,
|
|
87
|
+
timestamp: now(),
|
|
88
|
+
error: error.errorType.identifier,
|
|
89
|
+
message: error.description
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
**Import with full path:**
|
|
94
|
+
|
|
95
|
+
```dataweave
|
|
96
|
+
%dw 2.0
|
|
97
|
+
import dwl::modules::dateUtils
|
|
98
|
+
output application/json
|
|
99
|
+
---
|
|
100
|
+
{
|
|
101
|
+
createdDate: dateUtils::formatDate(payload.CreatedDate)
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
> ⚠️ **Critical:** Always use `dwl::modules::moduleName` as the import path. Short paths like `modules::moduleName` will compile but **fail at runtime**.
|
|
106
|
+
|
|
107
|
+
### Pattern 3: Type Coercion for Connectors
|
|
108
|
+
|
|
109
|
+
**Use when:** passing data to the Salesforce connector (or any connector that expects Java types).
|
|
110
|
+
|
|
111
|
+
The SF connector rejects ISO datetime strings — they must be Java DateTime objects:
|
|
112
|
+
|
|
113
|
+
```dataweave
|
|
114
|
+
// dwl/modules/salesforceUtility.dwl
|
|
115
|
+
%dw 2.0
|
|
116
|
+
|
|
117
|
+
var dateTimePattern = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{1,3})?(Z|[+-]\d{2}:\d{2})?$/
|
|
118
|
+
var dateOnlyPattern = /^\d{4}-\d{2}-\d{2}$/
|
|
119
|
+
|
|
120
|
+
fun parseAndConvert(obj: Object) =
|
|
121
|
+
obj mapObject ((value, key) ->
|
|
122
|
+
if ((value is String) and ((value as String) matches dateTimePattern))
|
|
123
|
+
(key): (value as String) as DateTime
|
|
124
|
+
else if ((value is String) and ((value as String) matches dateOnlyPattern))
|
|
125
|
+
(key): (value as String) as Date
|
|
126
|
+
else if ((value is String) and ((value as String) == ""))
|
|
127
|
+
(key): null
|
|
128
|
+
else if (value is Object)
|
|
129
|
+
(key): parseAndConvert(value)
|
|
130
|
+
else
|
|
131
|
+
(key): value
|
|
132
|
+
)
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
**When to use `output application/java`:**
|
|
136
|
+
|
|
137
|
+
```dataweave
|
|
138
|
+
%dw 2.0
|
|
139
|
+
import dwl::modules::salesforceUtility
|
|
140
|
+
output application/java // ← Required for SF connector inputs
|
|
141
|
+
---
|
|
142
|
+
salesforceUtility::parseAndConvert(payload)
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Use `output application/java` for transforms that feed directly into connectors (SF, DB, NetSuite SOAP). Use `output application/json` for HTTP response payloads.
|
|
146
|
+
|
|
147
|
+
### Pattern 4: Cross-System Value Mapping
|
|
148
|
+
|
|
149
|
+
**Use when:** translating enum/picklist values between systems (country codes, currency codes, payment terms, industry classifications). There are 4 strategies — choose based on your data characteristics.
|
|
150
|
+
|
|
151
|
+
#### Strategy A: Rich-Object DWL Lookup (Standardized Reference Data)
|
|
152
|
+
|
|
153
|
+
**Use when:** stable reference data (ISO countries, currencies), ≤ 300 entries, same across all environments, callers need multiple fields (`.name`, `.erp`).
|
|
154
|
+
|
|
155
|
+
```dataweave
|
|
156
|
+
// dwl/lookups/countryMap.dwl
|
|
157
|
+
%dw 2.0
|
|
158
|
+
|
|
159
|
+
fun countryMap() = {
|
|
160
|
+
"US": { "name": "United States", "erp": "_unitedStates" },
|
|
161
|
+
"CA": { "name": "Canada", "erp": "_canada" },
|
|
162
|
+
"GB": { "name": "United Kingdom", "erp": "_unitedKingdom" }
|
|
163
|
+
// 250+ entries for full ISO 3166...
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
**Usage — always null-guard before dereferencing:**
|
|
168
|
+
|
|
169
|
+
```dataweave
|
|
170
|
+
import countryMap from dwl::lookups::countryMap
|
|
171
|
+
---
|
|
172
|
+
{
|
|
173
|
+
(shippingCountry: countryMap()[payload.ShippingCountry].erp)
|
|
174
|
+
if (payload.ShippingCountry? and (countryMap()[payload.ShippingCountry] != null))
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
#### Strategy B: Environment-Specific JSON Dictionary
|
|
179
|
+
|
|
180
|
+
**Use when:** target system IDs differ between dev/staging/prod (e.g., ERP sandbox has different internal IDs than production). Flat key → value mapping loaded via `readUrl`.
|
|
181
|
+
|
|
182
|
+
```json
|
|
183
|
+
// dwl/dictionaries/customer-industry-dictionary-dev.json
|
|
184
|
+
{
|
|
185
|
+
"Education": "1",
|
|
186
|
+
"Financial Services": "13",
|
|
187
|
+
"Government": "14"
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
```json
|
|
192
|
+
// dwl/dictionaries/customer-industry-dictionary-prod.json
|
|
193
|
+
{
|
|
194
|
+
"Education": "101",
|
|
195
|
+
"Financial Services": "113",
|
|
196
|
+
"Government": "114"
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
**Load dynamically using environment property:**
|
|
201
|
+
|
|
202
|
+
```dataweave
|
|
203
|
+
var industry = readUrl(
|
|
204
|
+
"classpath://dwl/dictionaries/customer-industry-dictionary-$(p('mule.env')).json",
|
|
205
|
+
"application/json"
|
|
206
|
+
)
|
|
207
|
+
---
|
|
208
|
+
{
|
|
209
|
+
(industryId: industry[payload.Industry]) if (payload.Industry?)
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
#### Strategy C: Bidirectional DWL Module (Enum Translation)
|
|
214
|
+
|
|
215
|
+
**Use when:** business enums must translate in both directions (CRM → ERP and ERP → CRM), ≤ 50 values, stable values (payment terms, billing frequency).
|
|
216
|
+
|
|
217
|
+
**Option 1 — Computed inverse (recommended for 1:1 mappings):**
|
|
218
|
+
|
|
219
|
+
```dataweave
|
|
220
|
+
// dwl/lookups/paymentTerms.dwl
|
|
221
|
+
%dw 2.0
|
|
222
|
+
|
|
223
|
+
// Single source of truth
|
|
224
|
+
var crmToErp = {
|
|
225
|
+
"Net 15": "1", "Net 30": "2", "Net 45": "8",
|
|
226
|
+
"Net 60": "3", "Due on receipt": "4"
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// Auto-computed inverse — no dual maintenance
|
|
230
|
+
var erpToCrm = crmToErp pluck ((value, key) -> { (value): key as String })
|
|
231
|
+
reduce ((item, acc = {}) -> acc ++ item)
|
|
232
|
+
|
|
233
|
+
fun mapPaymentTermToERP(crmValue: String) = crmToErp[crmValue]
|
|
234
|
+
fun mapPaymentTermToCRM(erpId: String) = erpToCrm[erpId]
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
**Option 2 — Explicit dual dictionary (required for many-to-one):**
|
|
238
|
+
|
|
239
|
+
When 3 CRM statuses map to 1 ERP status, the computed inverse is ambiguous. Maintain both directions explicitly:
|
|
240
|
+
|
|
241
|
+
```dataweave
|
|
242
|
+
var statusMap = {
|
|
243
|
+
crmToErp: { "Open": "1", "In Progress": "1", "Closed": "2" },
|
|
244
|
+
erpToCrm: { "1": "Open", "2": "Closed" }
|
|
245
|
+
}
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
#### Strategy D: External API / ObjectStore Cache (Dynamic Catalogs)
|
|
249
|
+
|
|
250
|
+
**Use when:** > 500 values, business users manage mappings at runtime, multiple apps share the same mapping, change frequency > quarterly.
|
|
251
|
+
|
|
252
|
+
```xml
|
|
253
|
+
<os:object-store name="product-sku-cache"
|
|
254
|
+
entryTtl="3600000"
|
|
255
|
+
expirationInterval="300000"
|
|
256
|
+
maxEntries="500"/>
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
#### Decision Tree
|
|
260
|
+
|
|
261
|
+
```
|
|
262
|
+
Does the mapping differ between dev/staging/prod?
|
|
263
|
+
├── YES → Strategy B (Environment-Specific JSON Dictionary)
|
|
264
|
+
└── NO
|
|
265
|
+
├── Need lookup in both directions (CRM↔ERP)?
|
|
266
|
+
│ ├── YES, ≤ 50 values → Strategy C (Bidirectional DWL)
|
|
267
|
+
│ └── YES, > 50 values → Strategy D (External)
|
|
268
|
+
└── NO (one direction only)
|
|
269
|
+
├── Need rich objects (name + ID)? → Strategy A (Rich-Object DWL)
|
|
270
|
+
└── Simple key→value? → Strategy A (flat DWL function)
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
**Testing guidance:**
|
|
274
|
+
|
|
275
|
+
- **Completeness:** When CRM adds a new picklist value, the lookup silently returns `null`. Add MUnit tests that validate all known enum values have mappings.
|
|
276
|
+
- **Symmetry:** For 1:1 bidirectional mappings, `mapToERP(mapFromERP(x)) == x` should hold.
|
|
277
|
+
- **Environment parity:** For Strategy B, verify that dev and prod dictionary files have the **same keys** (only IDs should differ).
|
|
278
|
+
|
|
279
|
+
> ⚠️ **Always null-guard lookups** — `countryMap()[code]` returns `null` for unknown codes. Dereferencing `.erp` on `null` causes a runtime error.
|
|
280
|
+
|
|
281
|
+
### Pattern 5: Array Normalization for Connectors
|
|
282
|
+
|
|
283
|
+
**Use when:** connector operations (upsert, create, update) always expect arrays, but input may be a single object.
|
|
284
|
+
|
|
285
|
+
```dataweave
|
|
286
|
+
%dw 2.0
|
|
287
|
+
import dwl::modules::salesforceUtility
|
|
288
|
+
output application/java
|
|
289
|
+
---
|
|
290
|
+
var parsed = salesforceUtility::parseAndConvert(payload)
|
|
291
|
+
---
|
|
292
|
+
if (parsed is Array) parsed else [parsed]
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
### Pattern 6: Error Payload Template
|
|
296
|
+
|
|
297
|
+
**Use when:** building standardized error response payloads.
|
|
298
|
+
|
|
299
|
+
```dataweave
|
|
300
|
+
// dwl/transforms/error-payload.dwl
|
|
301
|
+
%dw 2.0
|
|
302
|
+
output application/json
|
|
303
|
+
---
|
|
304
|
+
{
|
|
305
|
+
timestamp: now() as String {format: "yyyy-MM-dd'T'HH:mm:ss.SSSZ"},
|
|
306
|
+
correlationId: vars.correlationId default "",
|
|
307
|
+
entity: vars.entity default "",
|
|
308
|
+
salesforceId: vars.salesforceId default "",
|
|
309
|
+
errorType: error.errorType.identifier default "UNKNOWN",
|
|
310
|
+
message: error.detailedDescription default error.description default "",
|
|
311
|
+
environment: p('mule.env')
|
|
312
|
+
}
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
---
|
|
316
|
+
|
|
317
|
+
## Java 17 DataWeave Considerations
|
|
318
|
+
|
|
319
|
+
Since Mule 4.9+ mandates Java 17:
|
|
320
|
+
|
|
321
|
+
- `try()` requires explicit import: `import try from dw::Runtime`
|
|
322
|
+
- `error.errorType.identifier` — use `.identifier`, not `.asString` (doesn't exist)
|
|
323
|
+
- Batch Kryo serialization — don't use `output application/java` for HTTP payloads in batch steps
|
|
324
|
+
- `DateTime` coercion is stricter in Java 17 — always test date parsing patterns
|
|
325
|
+
|
|
326
|
+
**Safe error description extraction using `try()`:**
|
|
327
|
+
|
|
328
|
+
```dataweave
|
|
329
|
+
%dw 2.0
|
|
330
|
+
import try from dw::Runtime
|
|
331
|
+
var errorDesc = try(() -> error.errorMessage.payload.errorDescription default "")
|
|
332
|
+
---
|
|
333
|
+
{
|
|
334
|
+
"Subject": "Failed to sync record",
|
|
335
|
+
"Error": if (errorDesc.success and !isBlank(errorDesc.result))
|
|
336
|
+
errorDesc.result
|
|
337
|
+
else (error.detailedDescription default "")
|
|
338
|
+
}
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
> ⚠️ Use `try()` when accessing deeply nested error properties that may not exist. Without it, accessing `error.errorMessage.payload.errorDescription` throws if `payload` is not an object.
|
|
342
|
+
|
|
343
|
+
---
|
|
344
|
+
|
|
345
|
+
## File Naming Convention
|
|
346
|
+
|
|
347
|
+
| Convention | Example | Use For |
|
|
348
|
+
| ------------ | ------------------------------ | -------------------------------------------- |
|
|
349
|
+
| `kebab-case` | `transform-order-response.dwl` | Transform files |
|
|
350
|
+
| `camelCase` | `salesforceUtility.dwl` | Module files (matches DWL import convention) |
|
|
351
|
+
| `kebab-case` | `country-map.dwl` | Lookup files |
|
|
352
|
+
|
|
353
|
+
> **Note:** Module filenames use `camelCase` because the DWL import path must match the filename exactly (`import dwl::modules::salesforceUtility`). Renaming to kebab-case would break imports.
|
|
354
|
+
|
|
355
|
+
---
|
|
356
|
+
|
|
357
|
+
## Checklist
|
|
358
|
+
|
|
359
|
+
- [ ] No inline DWL exceeding 5 lines — externalize to `.dwl` files
|
|
360
|
+
- [ ] Shared logic in `dwl/modules/` with full import path
|
|
361
|
+
- [ ] `output application/java` used for connector input transforms
|
|
362
|
+
- [ ] `output application/json` used for HTTP response transforms
|
|
363
|
+
- [ ] Type coercion applied before passing data to SF connector
|
|
364
|
+
- [ ] Lookup modules always null-guarded
|
|
365
|
+
- [ ] Array normalization before connector operations
|
|
366
|
+
- [ ] `.dwl` files have Javadoc-style header comments
|
|
367
|
+
|
|
368
|
+
---
|
|
369
|
+
|
|
370
|
+
**See also:** [Connector Patterns](connector-patterns.md) · [Documentation Standards](documentation-standards.md)
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
# Deployment & Modernization (2026)
|
|
2
|
+
|
|
3
|
+
> **Applies to:** All
|
|
4
|
+
> **Related Rules:** `OPS-001` · `PROJ-001` · `PROJ-002`
|
|
5
|
+
> **Last Updated:** April 2026
|
|
6
|
+
|
|
7
|
+
## When to Read This
|
|
8
|
+
|
|
9
|
+
Read this when planning deployments, migrating to Java 17, adopting CloudHub 2.0, or modernizing tooling.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Development Tooling (2026)
|
|
14
|
+
|
|
15
|
+
### Anypoint Code Builder (ACB)
|
|
16
|
+
|
|
17
|
+
ACB (VS Code-based) is the recommended IDE for 2026+, replacing Anypoint Studio for new projects:
|
|
18
|
+
|
|
19
|
+
- **AI-assisted development** via MuleSoft Vibes
|
|
20
|
+
- **AsyncAPI 2.6 support** for event-driven API design
|
|
21
|
+
- **Native API Governance** validation during design
|
|
22
|
+
- **Integrated Exchange** publishing
|
|
23
|
+
|
|
24
|
+
### MuleSoft CLI Tools
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
# Lint analysis (CI/CD and local)
|
|
28
|
+
npx @sfdxy/mule-lint . -c .mulelintrc.json -f json
|
|
29
|
+
|
|
30
|
+
# Build + test
|
|
31
|
+
mvn clean test -Dmule.env=dev -Dsecure.key=test
|
|
32
|
+
|
|
33
|
+
# Package
|
|
34
|
+
mvn clean package -DskipTests
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Java 17 Migration
|
|
40
|
+
|
|
41
|
+
Mule 4.9+ **mandates Java 17**. Migration checklist:
|
|
42
|
+
|
|
43
|
+
- [ ] Update `pom.xml` compiler settings and runtime version
|
|
44
|
+
- [ ] Run `jdeps` to identify dependencies on removed Java APIs
|
|
45
|
+
- [ ] Audit connector compatibility (most modern connectors are Java 17 compatible)
|
|
46
|
+
- [ ] Recompile custom connectors and Java modules
|
|
47
|
+
- [ ] Test DataWeave patterns — `DateTime` coercion is stricter in Java 17
|
|
48
|
+
- [ ] Update `log4j2.xml` for Java 17 module system changes
|
|
49
|
+
- [ ] Performance test in staging — JIT compiler and GC behavior differ
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Deployment Models
|
|
54
|
+
|
|
55
|
+
### CloudHub 2.0 (Kubernetes-based)
|
|
56
|
+
|
|
57
|
+
| Feature | CloudHub 1.0 | CloudHub 2.0 |
|
|
58
|
+
| ------------------ | -------------------- | --------------------------------- |
|
|
59
|
+
| **Infrastructure** | VM-based workers | Kubernetes pods |
|
|
60
|
+
| **Scaling** | vCore-based | Pod replicas + HPA |
|
|
61
|
+
| **Networking** | Shared Load Balancer | Ingress / private networking |
|
|
62
|
+
| **Persistence** | Object Store V1 | Object Store V2 (pod-local) |
|
|
63
|
+
| **Monitoring** | Anypoint Monitoring | Anypoint Monitoring + K8s metrics |
|
|
64
|
+
|
|
65
|
+
### Runtime Fabric (RTF)
|
|
66
|
+
|
|
67
|
+
For hybrid or private cloud deployments:
|
|
68
|
+
|
|
69
|
+
- Self-managed Kubernetes clusters
|
|
70
|
+
- Air-gapped environments
|
|
71
|
+
- Regulatory compliance (data residency)
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## Environment Promotion
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
Development → QA → Staging → Production
|
|
79
|
+
↓ ↓ ↓ ↓
|
|
80
|
+
dev.yaml qa.yaml stg.yaml prod.yaml
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Deployment Checklist
|
|
84
|
+
|
|
85
|
+
| Item | Description |
|
|
86
|
+
| ------------------------ | ----------------------------- |
|
|
87
|
+
| ✅ All tests pass | MUnit and integration tests |
|
|
88
|
+
| ✅ Lint checks pass | No errors from mule-lint |
|
|
89
|
+
| ✅ Properties configured | Environment YAML verified |
|
|
90
|
+
| ✅ Secrets encrypted | No plaintext credentials |
|
|
91
|
+
| ✅ API Manager policies | Authentication, rate limiting |
|
|
92
|
+
| ✅ Monitoring configured | Dashboards and alerts ready |
|
|
93
|
+
| ✅ Java 17 verified | Runtime compatible |
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## API Governance at Design Time
|
|
98
|
+
|
|
99
|
+
Before publishing to Exchange, validate API specifications against organizational rulesets:
|
|
100
|
+
|
|
101
|
+
1. Define governance rulesets in API Governance
|
|
102
|
+
2. Validate RAML/OAS/AsyncAPI specs during design in ACB
|
|
103
|
+
3. Block publishing to Exchange if governance rules fail
|
|
104
|
+
4. Automate governance checks in CI/CD pipeline
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## API Versioning
|
|
109
|
+
|
|
110
|
+
### URL-Based Versioning (Recommended)
|
|
111
|
+
|
|
112
|
+
```
|
|
113
|
+
/api/v1/orders
|
|
114
|
+
/api/v2/orders
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Deprecation Strategy
|
|
118
|
+
|
|
119
|
+
1. Announce deprecation timeline to consumers
|
|
120
|
+
2. Return `Deprecation` and `Sunset` headers
|
|
121
|
+
3. Monitor v1 vs v2 adoption
|
|
122
|
+
4. Sunset after consumer migration
|
|
123
|
+
|
|
124
|
+
```xml
|
|
125
|
+
<set-variable variableName="outboundHeaders" value="#[{
|
|
126
|
+
'Deprecation': 'true',
|
|
127
|
+
'Sunset': 'Sat, 01 Jan 2027 00:00:00 GMT',
|
|
128
|
+
'Link': '</api/v2/orders>; rel=\"successor-version\"'
|
|
129
|
+
}]"/>
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## Monitoring & Observability
|
|
135
|
+
|
|
136
|
+
### Three Pillars
|
|
137
|
+
|
|
138
|
+
| Pillar | Tool | Purpose |
|
|
139
|
+
| ----------- | ----------------------------------- | --------------------- |
|
|
140
|
+
| **Logs** | Anypoint Monitoring, Splunk, ELK | Debug, audit trail |
|
|
141
|
+
| **Metrics** | Anypoint Monitoring, Grafana | Performance, health |
|
|
142
|
+
| **Traces** | Anypoint Monitoring, Tracing module | Request flow, latency |
|
|
143
|
+
|
|
144
|
+
### Key Metrics to Monitor
|
|
145
|
+
|
|
146
|
+
```
|
|
147
|
+
Application Health:
|
|
148
|
+
├── Response time (p50, p95, p99)
|
|
149
|
+
├── Error rate (%)
|
|
150
|
+
├── Throughput (requests/sec)
|
|
151
|
+
├── Active connections
|
|
152
|
+
└── Worker CPU/Memory usage
|
|
153
|
+
|
|
154
|
+
Business Metrics:
|
|
155
|
+
├── Records processed per hour
|
|
156
|
+
├── Failed transactions
|
|
157
|
+
├── API calls by consumer
|
|
158
|
+
└── Integration latency by backend
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Alerting
|
|
162
|
+
|
|
163
|
+
| Level | Condition | Response |
|
|
164
|
+
| ------------ | ------------------------------- | ----------------------- |
|
|
165
|
+
| **Critical** | Error rate > 10%, App down | Immediate on-call |
|
|
166
|
+
| **Warning** | Error rate > 5%, Latency > 5s | Investigate within 1h |
|
|
167
|
+
| **Info** | Resource > 70%, unusual pattern | Review in daily standup |
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
**See also:** [CI/CD Integration](ci-cd.md) · [Security](security.md) · [Testing](testing.md)
|