@sfdxy/mule-lint 1.20.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.
Files changed (156) hide show
  1. package/README.md +63 -17
  2. package/dist/package.json +1 -1
  3. package/dist/src/core/XPathHelper.d.ts.map +1 -1
  4. package/dist/src/core/XPathHelper.js +8 -0
  5. package/dist/src/core/XPathHelper.js.map +1 -1
  6. package/dist/src/engine/LintEngine.d.ts +22 -0
  7. package/dist/src/engine/LintEngine.d.ts.map +1 -1
  8. package/dist/src/engine/LintEngine.js +105 -18
  9. package/dist/src/engine/LintEngine.js.map +1 -1
  10. package/dist/src/mcp/prompts/index.d.ts +1 -1
  11. package/dist/src/mcp/prompts/index.d.ts.map +1 -1
  12. package/dist/src/mcp/prompts/index.js +62 -1
  13. package/dist/src/mcp/prompts/index.js.map +1 -1
  14. package/dist/src/mcp/resources/index.js +114 -16
  15. package/dist/src/mcp/resources/index.js.map +1 -1
  16. package/dist/src/mcp/tools/getRuleDetails.d.ts.map +1 -1
  17. package/dist/src/mcp/tools/getRuleDetails.js +30 -1
  18. package/dist/src/mcp/tools/getRuleDetails.js.map +1 -1
  19. package/dist/src/rules/api-led/ApikitConsoleProductionRule.d.ts +22 -0
  20. package/dist/src/rules/api-led/ApikitConsoleProductionRule.d.ts.map +1 -0
  21. package/dist/src/rules/api-led/ApikitConsoleProductionRule.js +43 -0
  22. package/dist/src/rules/api-led/ApikitConsoleProductionRule.js.map +1 -0
  23. package/dist/src/rules/api-led/ApikitMainFlowStructureRule.d.ts +24 -0
  24. package/dist/src/rules/api-led/ApikitMainFlowStructureRule.d.ts.map +1 -0
  25. package/dist/src/rules/api-led/ApikitMainFlowStructureRule.js +53 -0
  26. package/dist/src/rules/api-led/ApikitMainFlowStructureRule.js.map +1 -0
  27. package/dist/src/rules/api-led/ApikitStatusCodeVariableRule.d.ts +25 -0
  28. package/dist/src/rules/api-led/ApikitStatusCodeVariableRule.d.ts.map +1 -0
  29. package/dist/src/rules/api-led/ApikitStatusCodeVariableRule.js +59 -0
  30. package/dist/src/rules/api-led/ApikitStatusCodeVariableRule.js.map +1 -0
  31. package/dist/src/rules/connector/EventListenerNullGuardRule.d.ts +24 -0
  32. package/dist/src/rules/connector/EventListenerNullGuardRule.d.ts.map +1 -0
  33. package/dist/src/rules/connector/EventListenerNullGuardRule.js +58 -0
  34. package/dist/src/rules/connector/EventListenerNullGuardRule.js.map +1 -0
  35. package/dist/src/rules/connector/ReplayChannelConfigRule.d.ts +23 -0
  36. package/dist/src/rules/connector/ReplayChannelConfigRule.d.ts.map +1 -0
  37. package/dist/src/rules/connector/ReplayChannelConfigRule.js +52 -0
  38. package/dist/src/rules/connector/ReplayChannelConfigRule.js.map +1 -0
  39. package/dist/src/rules/dataweave/DataWeaveRules.d.ts +11 -4
  40. package/dist/src/rules/dataweave/DataWeaveRules.d.ts.map +1 -1
  41. package/dist/src/rules/dataweave/DataWeaveRules.js +20 -20
  42. package/dist/src/rules/dataweave/DataWeaveRules.js.map +1 -1
  43. package/dist/src/rules/dataweave/DuplicateTransformLogicRule.d.ts +25 -0
  44. package/dist/src/rules/dataweave/DuplicateTransformLogicRule.d.ts.map +1 -0
  45. package/dist/src/rules/dataweave/DuplicateTransformLogicRule.js +63 -0
  46. package/dist/src/rules/dataweave/DuplicateTransformLogicRule.js.map +1 -0
  47. package/dist/src/rules/error-handling/CatchAllLastRule.d.ts +24 -0
  48. package/dist/src/rules/error-handling/CatchAllLastRule.d.ts.map +1 -0
  49. package/dist/src/rules/error-handling/CatchAllLastRule.js +65 -0
  50. package/dist/src/rules/error-handling/CatchAllLastRule.js.map +1 -0
  51. package/dist/src/rules/error-handling/ErrorHandlerTypeCoverageRule.d.ts +28 -0
  52. package/dist/src/rules/error-handling/ErrorHandlerTypeCoverageRule.d.ts.map +1 -0
  53. package/dist/src/rules/error-handling/ErrorHandlerTypeCoverageRule.js +70 -0
  54. package/dist/src/rules/error-handling/ErrorHandlerTypeCoverageRule.js.map +1 -0
  55. package/dist/src/rules/error-handling/ErrorResponseStructureRule.d.ts +23 -0
  56. package/dist/src/rules/error-handling/ErrorResponseStructureRule.d.ts.map +1 -0
  57. package/dist/src/rules/error-handling/ErrorResponseStructureRule.js +73 -0
  58. package/dist/src/rules/error-handling/ErrorResponseStructureRule.js.map +1 -0
  59. package/dist/src/rules/error-handling/GenericErrorRule.d.ts +15 -3
  60. package/dist/src/rules/error-handling/GenericErrorRule.d.ts.map +1 -1
  61. package/dist/src/rules/error-handling/GenericErrorRule.js +58 -18
  62. package/dist/src/rules/error-handling/GenericErrorRule.js.map +1 -1
  63. package/dist/src/rules/error-handling/GlobalErrorHandlerRule.d.ts +14 -15
  64. package/dist/src/rules/error-handling/GlobalErrorHandlerRule.d.ts.map +1 -1
  65. package/dist/src/rules/error-handling/GlobalErrorHandlerRule.js +59 -38
  66. package/dist/src/rules/error-handling/GlobalErrorHandlerRule.js.map +1 -1
  67. package/dist/src/rules/error-handling/TryScopeRule.d.ts +5 -0
  68. package/dist/src/rules/error-handling/TryScopeRule.d.ts.map +1 -1
  69. package/dist/src/rules/error-handling/TryScopeRule.js +30 -7
  70. package/dist/src/rules/error-handling/TryScopeRule.js.map +1 -1
  71. package/dist/src/rules/http/ConnectionIdleTimeoutRule.d.ts +27 -0
  72. package/dist/src/rules/http/ConnectionIdleTimeoutRule.d.ts.map +1 -0
  73. package/dist/src/rules/http/ConnectionIdleTimeoutRule.js +46 -0
  74. package/dist/src/rules/http/ConnectionIdleTimeoutRule.js.map +1 -0
  75. package/dist/src/rules/index.d.ts +1 -1
  76. package/dist/src/rules/index.d.ts.map +1 -1
  77. package/dist/src/rules/index.js +50 -8
  78. package/dist/src/rules/index.js.map +1 -1
  79. package/dist/src/rules/logging/LoggerPayloadRule.d.ts +15 -0
  80. package/dist/src/rules/logging/LoggerPayloadRule.d.ts.map +1 -1
  81. package/dist/src/rules/logging/LoggerPayloadRule.js +48 -4
  82. package/dist/src/rules/logging/LoggerPayloadRule.js.map +1 -1
  83. package/dist/src/rules/operations/FlowRefTargetExistsRule.d.ts +23 -0
  84. package/dist/src/rules/operations/FlowRefTargetExistsRule.d.ts.map +1 -0
  85. package/dist/src/rules/operations/FlowRefTargetExistsRule.js +58 -0
  86. package/dist/src/rules/operations/FlowRefTargetExistsRule.js.map +1 -0
  87. package/dist/src/rules/operations/UnusedFlowRule.d.ts +20 -0
  88. package/dist/src/rules/operations/UnusedFlowRule.d.ts.map +1 -1
  89. package/dist/src/rules/operations/UnusedFlowRule.js +73 -7
  90. package/dist/src/rules/operations/UnusedFlowRule.js.map +1 -1
  91. package/dist/src/rules/operations/UnusedVariableRule.d.ts +31 -0
  92. package/dist/src/rules/operations/UnusedVariableRule.d.ts.map +1 -0
  93. package/dist/src/rules/operations/UnusedVariableRule.js +103 -0
  94. package/dist/src/rules/operations/UnusedVariableRule.js.map +1 -0
  95. package/dist/src/rules/performance/ListenerReconnectForeverRule.d.ts +28 -0
  96. package/dist/src/rules/performance/ListenerReconnectForeverRule.d.ts.map +1 -0
  97. package/dist/src/rules/performance/ListenerReconnectForeverRule.js +56 -0
  98. package/dist/src/rules/performance/ListenerReconnectForeverRule.js.map +1 -0
  99. package/dist/src/rules/performance/ReconnectionStrategyRule.d.ts +7 -4
  100. package/dist/src/rules/performance/ReconnectionStrategyRule.d.ts.map +1 -1
  101. package/dist/src/rules/performance/ReconnectionStrategyRule.js +44 -24
  102. package/dist/src/rules/performance/ReconnectionStrategyRule.js.map +1 -1
  103. package/dist/src/rules/security/ConnectorCredentialsSecuredRule.d.ts +36 -0
  104. package/dist/src/rules/security/ConnectorCredentialsSecuredRule.d.ts.map +1 -0
  105. package/dist/src/rules/security/ConnectorCredentialsSecuredRule.js +124 -0
  106. package/dist/src/rules/security/ConnectorCredentialsSecuredRule.js.map +1 -0
  107. package/dist/src/rules/security/HardcodedCredentialsRule.d.ts +4 -0
  108. package/dist/src/rules/security/HardcodedCredentialsRule.d.ts.map +1 -1
  109. package/dist/src/rules/security/HardcodedCredentialsRule.js +15 -0
  110. package/dist/src/rules/security/HardcodedCredentialsRule.js.map +1 -1
  111. package/dist/src/rules/security/SecurePropertiesEncryptionRule.d.ts +25 -0
  112. package/dist/src/rules/security/SecurePropertiesEncryptionRule.d.ts.map +1 -0
  113. package/dist/src/rules/security/SecurePropertiesEncryptionRule.js +59 -0
  114. package/dist/src/rules/security/SecurePropertiesEncryptionRule.js.map +1 -0
  115. package/dist/src/rules/security/SecurePropertiesKeyRule.d.ts +23 -0
  116. package/dist/src/rules/security/SecurePropertiesKeyRule.d.ts.map +1 -0
  117. package/dist/src/rules/security/SecurePropertiesKeyRule.js +45 -0
  118. package/dist/src/rules/security/SecurePropertiesKeyRule.js.map +1 -0
  119. package/dist/src/rules/security/TlsKeystorePasswordRule.d.ts +25 -0
  120. package/dist/src/rules/security/TlsKeystorePasswordRule.d.ts.map +1 -0
  121. package/dist/src/rules/security/TlsKeystorePasswordRule.js +63 -0
  122. package/dist/src/rules/security/TlsKeystorePasswordRule.js.map +1 -0
  123. package/dist/src/rules/standards/ApikitRouteVariableConsistencyRule.d.ts +26 -0
  124. package/dist/src/rules/standards/ApikitRouteVariableConsistencyRule.d.ts.map +1 -0
  125. package/dist/src/rules/standards/ApikitRouteVariableConsistencyRule.js +61 -0
  126. package/dist/src/rules/standards/ApikitRouteVariableConsistencyRule.js.map +1 -0
  127. package/dist/src/rules/standards/ConfigPropertiesOrderingRule.d.ts +34 -0
  128. package/dist/src/rules/standards/ConfigPropertiesOrderingRule.d.ts.map +1 -0
  129. package/dist/src/rules/standards/ConfigPropertiesOrderingRule.js +76 -0
  130. package/dist/src/rules/standards/ConfigPropertiesOrderingRule.js.map +1 -0
  131. package/dist/src/rules/standards/MissingEnvPropertiesDeclarationRule.d.ts +25 -0
  132. package/dist/src/rules/standards/MissingEnvPropertiesDeclarationRule.d.ts.map +1 -0
  133. package/dist/src/rules/standards/MissingEnvPropertiesDeclarationRule.js +111 -0
  134. package/dist/src/rules/standards/MissingEnvPropertiesDeclarationRule.js.map +1 -0
  135. package/dist/src/rules/yaml/YamlRules.d.ts +6 -2
  136. package/dist/src/rules/yaml/YamlRules.d.ts.map +1 -1
  137. package/dist/src/rules/yaml/YamlRules.js +15 -11
  138. package/dist/src/rules/yaml/YamlRules.js.map +1 -1
  139. package/dist/src/types/Rule.d.ts +13 -0
  140. package/dist/src/types/Rule.d.ts.map +1 -1
  141. package/docs/README.md +87 -27
  142. package/docs/best-practices/ci-cd.md +135 -0
  143. package/docs/best-practices/connector-patterns.md +253 -0
  144. package/docs/best-practices/dataweave-patterns.md +370 -0
  145. package/docs/best-practices/deployment-2026.md +171 -0
  146. package/docs/best-practices/error-handling.md +277 -0
  147. package/docs/best-practices/event-driven-patterns.md +424 -0
  148. package/docs/best-practices/logging.md +163 -0
  149. package/docs/best-practices/mulesoft-best-practices.md +72 -865
  150. package/docs/best-practices/performance.md +273 -0
  151. package/docs/best-practices/rules-catalog.md +337 -29
  152. package/docs/best-practices/security.md +181 -0
  153. package/docs/best-practices/testing.md +190 -0
  154. package/docs/best-practices/variable-contracts.md +191 -0
  155. package/docs/linter/architecture.md +119 -64
  156. package/package.json +1 -1
@@ -0,0 +1,273 @@
1
+ # Performance Best Practices
2
+
3
+ > **Applies to:** All
4
+ > **Related Rules:** `MULE-501` · `MULE-502` · `MULE-503` · `PERF-002` · `RES-001` · `RES-002` · `MULE-801`
5
+ > **Last Updated:** April 2026
6
+
7
+ ## When to Read This
8
+
9
+ Read this when optimizing flow performance, configuring connection pooling, implementing async patterns, or reviewing a project for production readiness.
10
+
11
+ ---
12
+
13
+ ## Key Principles
14
+
15
+ 1. **Set explicit timeouts** — avoid hanging connections and resource leaks
16
+ 2. **Handle async errors** — async scopes silently swallow errors
17
+ 3. **Limit choice complexity** — refactor large choice blocks to DWL lookups
18
+ 4. **Configure connection pools** — essential for production throughput
19
+ 5. **Use streaming for large payloads** — avoid loading everything into memory
20
+
21
+ ---
22
+
23
+ ## Patterns
24
+
25
+ ### Pattern 1: Async Scope Error Handling
26
+
27
+ Async scopes don't propagate errors to the parent flow — they're silently lost:
28
+
29
+ ```xml
30
+ <!-- ❌ Bad — errors silently swallowed -->
31
+ <async>
32
+ <http:request config-ref="HTTP_Config" path="/webhook"/>
33
+ </async>
34
+
35
+ <!-- ✅ Good — explicit error handling inside async -->
36
+ <async>
37
+ <try>
38
+ <http:request config-ref="HTTP_Config" path="/webhook"/>
39
+ <error-handler>
40
+ <on-error-continue>
41
+ <logger category="com.myorg.async" level="ERROR"
42
+ message="#['Async webhook failed: ' ++ error.description]"/>
43
+ </on-error-continue>
44
+ </error-handler>
45
+ </try>
46
+ </async>
47
+ ```
48
+
49
+ ### Pattern 2: Refactor Large Choice Blocks
50
+
51
+ ```xml
52
+ <!-- ❌ Bad — too many when clauses (> 5) -->
53
+ <choice>
54
+ <when expression="#[vars.status == 'NEW']">...</when>
55
+ <when expression="#[vars.status == 'PENDING']">...</when>
56
+ <when expression="#[vars.status == 'APPROVED']">...</when>
57
+ <!-- 10+ more conditions -->
58
+ <otherwise>...</otherwise>
59
+ </choice>
60
+
61
+ <!-- ✅ Good — DataWeave lookup + dynamic flow-ref -->
62
+ <ee:transform>
63
+ <ee:set-variable variableName="handler"><![CDATA[%dw 2.0
64
+ var handlers = {
65
+ "NEW": "new-handler-subflow",
66
+ "PENDING": "pending-handler-subflow",
67
+ "APPROVED": "approved-handler-subflow"
68
+ }
69
+ ---
70
+ handlers[vars.status] default "default-handler-subflow"
71
+ ]]></ee:set-variable>
72
+ </ee:transform>
73
+ <flow-ref name="#[vars.handler]"/>
74
+ ```
75
+
76
+ ### Pattern 3: HTTP Timeout Configuration
77
+
78
+ ```xml
79
+ <!-- ✅ Always set explicit timeouts -->
80
+ <http:request-config name="API_Config"
81
+ responseTimeout="${https.request.responseTimeout}">
82
+ <http:request-connection host="${api.host}" port="${api.port}">
83
+ <http:client-socket-properties>
84
+ <http:tcp-client-socket-properties connectionTimeout="30000"/>
85
+ </http:client-socket-properties>
86
+ </http:request-connection>
87
+ </http:request-config>
88
+ ```
89
+
90
+ > ⚠️ **Grizzly rule:** `connectionIdleTimeout` must be ≥ `responseTimeout`. If idle timeout fires first, it kills the connection before the response arrives.
91
+
92
+ ### Pattern 4: Connection Pooling
93
+
94
+ ```xml
95
+ <!-- ✅ Good — HTTP with pooling configured -->
96
+ <http:request-config name="API_Config">
97
+ <http:request-connection host="${api.host}" port="${api.port}"
98
+ maxConnections="20"
99
+ connectionIdleTimeout="300000"/>
100
+ </http:request-config>
101
+
102
+ <!-- ✅ Good — Database with pooling -->
103
+ <db:config name="Database_Config">
104
+ <db:my-sql-connection host="${db.host}" port="${db.port}"
105
+ database="${db.name}" user="${db.user}"
106
+ password="${secure::db.password}">
107
+ <db:pooling-profile maxPoolSize="10"
108
+ minPoolSize="2" maxWait="30000"/>
109
+ </db:my-sql-connection>
110
+ </db:config>
111
+ ```
112
+
113
+ ### Pattern 5: Scatter-Gather Limits
114
+
115
+ Keep parallel routes manageable (< 5–7 routes):
116
+
117
+ ```xml
118
+ <scatter-gather>
119
+ <route><flow-ref name="service1-subflow"/></route>
120
+ <route><flow-ref name="service2-subflow"/></route>
121
+ <route><flow-ref name="service3-subflow"/></route>
122
+ </scatter-gather>
123
+ ```
124
+
125
+ ### Pattern 6: Streaming for Large Payloads
126
+
127
+ Mule 4 uses **file-stored repeatable streams** by default (512 KB in-memory buffer). For large payloads:
128
+
129
+ - **Don't** call `payload` multiple times — it forces stream re-read
130
+ - **Do** store needed values in variables before consuming the stream
131
+ - **Do** use streaming-compatible connectors and DataWeave
132
+
133
+ ```xml
134
+ <!-- ✅ Store needed values before processing -->
135
+ <set-variable variableName="recordCount" value="#[sizeOf(payload)]"/>
136
+ <ee:transform>
137
+ <ee:set-payload resource="dwl/transforms/process-batch.dwl"/>
138
+ </ee:transform>
139
+ ```
140
+
141
+ ### Pattern 7: Pre-batch Bulk Lookup (N+1 Prevention)
142
+
143
+ **Use when:** iterating over 10+ records with `foreach` where each record requires 1+ related record lookups from an external system. Without this pattern, 100 records × 3 lookups = 300 API calls. With it: 3 API calls.
144
+
145
+ **Do NOT use when:** iterating < 5 records (overhead not worth it), lookups are already cached in ObjectStore, or the downstream system doesn't support bulk/IN queries.
146
+
147
+ | Scenario | Bulk Lookup? | Why |
148
+ | ------------------------------------------ | ------------ | ------------------------ |
149
+ | 100 records, each needs 3 related lookups | ✅ | 300 calls → 3 calls |
150
+ | 3 records, each needs 1 lookup | ❌ | Overhead exceeds savings |
151
+ | Lookups already cached in ObjectStore | ❌ | Already optimized |
152
+ | Downstream doesn't support IN/bulk queries | ❌ | Can't batch anyway |
153
+
154
+ **Architecture:**
155
+
156
+ ```
157
+ 1. Save batch to variable
158
+ 2. Extract unique lookup IDs (distinctBy, filter !isEmpty)
159
+ 3. Scatter-gather: bulk-fetch all related records in parallel
160
+ 4. Build groupBy lookup maps → O(1) resolution per record
161
+ 5. Restore original batch as payload
162
+ 6. Foreach: resolve from maps (zero API calls)
163
+ ```
164
+
165
+ **Implementation:**
166
+
167
+ ```xml
168
+ <sub-flow name="bulkResolveLookupsSubFlow">
169
+ <!-- 1. Save the original batch -->
170
+ <set-variable value="#[payload]" variableName="batch"/>
171
+
172
+ <!-- 2. Extract unique lookup IDs -->
173
+ <ee:transform>
174
+ <ee:variables>
175
+ <ee:set-variable variableName="lookupIds"><![CDATA[%dw 2.0
176
+ output application/java
177
+ ---
178
+ {
179
+ projectIds: (vars.batch.projectId default [])
180
+ filter (!isEmpty($)) distinctBy $,
181
+ contactIds: (vars.batch.contactId default [])
182
+ filter (!isEmpty($)) distinctBy $
183
+ }]]></ee:set-variable>
184
+ </ee:variables>
185
+ </ee:transform>
186
+
187
+ <!-- 3. Bulk fetch in parallel -->
188
+ <scatter-gather>
189
+ <route>
190
+ <http:request method="GET" path="/Project__c">
191
+ <http:query-params>#[output application/java --- {
192
+ "query": "SELECT Id, Project_ID__c FROM Project__c
193
+ WHERE Project_ID__c IN ('"
194
+ ++ (vars.lookupIds.projectIds joinBy "','") ++ "')"
195
+ }]</http:query-params>
196
+ </http:request>
197
+ </route>
198
+ <route>
199
+ <http:request method="GET" path="/Contact">
200
+ <http:query-params>#[output application/java --- {
201
+ "query": "SELECT Id, AccountId FROM Contact
202
+ WHERE Id IN ('"
203
+ ++ (vars.lookupIds.contactIds joinBy "','") ++ "')"
204
+ }]</http:query-params>
205
+ </http:request>
206
+ </route>
207
+ </scatter-gather>
208
+
209
+ <!-- 4. Build lookup maps with groupBy -->
210
+ <ee:transform>
211
+ <ee:variables>
212
+ <ee:set-variable variableName="lookupMaps"><![CDATA[%dw 2.0
213
+ output application/java
214
+ ---
215
+ {
216
+ projects: (payload.'0'.payload default []) groupBy $.Project_ID__c,
217
+ contacts: (payload.'1'.payload default []) groupBy $.Id
218
+ }]]></ee:set-variable>
219
+ </ee:variables>
220
+ </ee:transform>
221
+
222
+ <!-- 5. Restore original batch (scatter-gather replaced payload) -->
223
+ <set-payload value="#[vars.batch]"/>
224
+ </sub-flow>
225
+ ```
226
+
227
+ **Then in the foreach — zero API calls per iteration:**
228
+
229
+ ```dataweave
230
+ var resolvedProject = (vars.lookupMaps.projects[payload.projectId] default [])[0]
231
+ ---
232
+ {
233
+ message: payload ++ { resolvedProject: resolvedProject },
234
+ recordType: "scheduled-entity"
235
+ }
236
+ ```
237
+
238
+ **Key rules:**
239
+
240
+ - **Always save-and-restore payload** — `scatter-gather` replaces `payload` with its own result object
241
+ - **`distinctBy $`** — deduplicate IDs (same project may appear on 50 records)
242
+ - **`filter !isEmpty($)`** — exclude null/empty IDs before building the IN clause
243
+ - **`groupBy` for O(1) resolution** — returns an array; take `[0]` for the first match
244
+ - **Guard the scatter-gather** — if no IDs exist, skip the bulk fetch entirely (set empty maps)
245
+
246
+ ---
247
+
248
+ ## Flow Complexity Guidelines
249
+
250
+ | Metric | Threshold | Action |
251
+ | --------------------- | ---------- | ----------------------- |
252
+ | Processors per flow | ≤ 15 | Split into sub-flows |
253
+ | Choice branches | ≤ 5 | Use DWL lookup pattern |
254
+ | Scatter-gather routes | ≤ 7 | Consolidate or sequence |
255
+ | Flow-ref depth | ≤ 5 levels | Flatten chain |
256
+ | Loggers per flow | ≤ 5 | Move to DEBUG level |
257
+
258
+ ---
259
+
260
+ ## Checklist
261
+
262
+ - [ ] `responseTimeout` set on all HTTP request configs
263
+ - [ ] `connectionIdleTimeout >= responseTimeout` (Grizzly rule)
264
+ - [ ] Connection pooling configured for HTTP and Database connectors
265
+ - [ ] Async scopes have internal error handling
266
+ - [ ] Choice blocks have ≤ 5 branches (refactor large ones)
267
+ - [ ] Scatter-gather has ≤ 7 routes
268
+ - [ ] Reconnection strategies on all outbound connectors
269
+ - [ ] Pre-batch bulk lookup used for foreach with 10+ records needing related lookups (Pattern 7)
270
+
271
+ ---
272
+
273
+ **See also:** [Connector Patterns](connector-patterns.md) · [Error Handling](error-handling.md)