@cloudstreamsoftware/claude-tools 1.0.0 → 1.1.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/README.md +152 -37
- package/agents/INDEX.md +183 -0
- package/agents/architect.md +247 -0
- package/agents/build-error-resolver.md +555 -0
- package/agents/catalyst-deployer.md +132 -0
- package/agents/code-reviewer.md +121 -0
- package/agents/compliance-auditor.md +148 -0
- package/agents/creator-architect.md +395 -0
- package/agents/deluge-reviewer.md +98 -0
- package/agents/doc-updater.md +471 -0
- package/agents/e2e-runner.md +711 -0
- package/agents/planner.md +122 -0
- package/agents/refactor-cleaner.md +309 -0
- package/agents/security-reviewer.md +582 -0
- package/agents/tdd-guide.md +302 -0
- package/config/versions.json +63 -0
- package/dist/hooks/hooks.json +209 -0
- package/dist/index.js +47 -0
- package/dist/lib/asset-value.js +609 -0
- package/dist/lib/client-manager.js +300 -0
- package/dist/lib/command-matcher.js +242 -0
- package/dist/lib/cross-session-patterns.js +754 -0
- package/dist/lib/intent-classifier.js +1075 -0
- package/dist/lib/package-manager.js +374 -0
- package/dist/lib/recommendation-engine.js +597 -0
- package/dist/lib/session-memory.js +489 -0
- package/dist/lib/skill-effectiveness.js +486 -0
- package/dist/lib/skill-matcher.js +595 -0
- package/dist/lib/tutorial-metrics.js +242 -0
- package/dist/lib/tutorial-progress.js +209 -0
- package/dist/lib/tutorial-renderer.js +431 -0
- package/dist/lib/utils.js +380 -0
- package/dist/lib/verify-formatter.js +143 -0
- package/dist/lib/workflow-state.js +249 -0
- package/hooks/hooks.json +209 -0
- package/package.json +5 -1
- package/scripts/aggregate-sessions.js +290 -0
- package/scripts/branch-name-validator.js +291 -0
- package/scripts/build.js +101 -0
- package/scripts/commands/client-switch.js +231 -0
- package/scripts/deprecate-skill.js +610 -0
- package/scripts/diagnose.js +324 -0
- package/scripts/doc-freshness.js +168 -0
- package/scripts/generate-weekly-digest.js +393 -0
- package/scripts/health-check.js +270 -0
- package/scripts/hooks/credential-check.js +101 -0
- package/scripts/hooks/evaluate-session.js +81 -0
- package/scripts/hooks/pre-compact.js +66 -0
- package/scripts/hooks/prompt-analyzer.js +276 -0
- package/scripts/hooks/prompt-router.js +422 -0
- package/scripts/hooks/quality-gate-enforcer.js +371 -0
- package/scripts/hooks/session-end.js +156 -0
- package/scripts/hooks/session-start.js +195 -0
- package/scripts/hooks/skill-injector.js +333 -0
- package/scripts/hooks/suggest-compact.js +58 -0
- package/scripts/lib/asset-value.js +609 -0
- package/scripts/lib/client-manager.js +300 -0
- package/scripts/lib/command-matcher.js +242 -0
- package/scripts/lib/cross-session-patterns.js +754 -0
- package/scripts/lib/intent-classifier.js +1075 -0
- package/scripts/lib/package-manager.js +374 -0
- package/scripts/lib/recommendation-engine.js +597 -0
- package/scripts/lib/session-memory.js +489 -0
- package/scripts/lib/skill-effectiveness.js +486 -0
- package/scripts/lib/skill-matcher.js +595 -0
- package/scripts/lib/tutorial-metrics.js +242 -0
- package/scripts/lib/tutorial-progress.js +209 -0
- package/scripts/lib/tutorial-renderer.js +431 -0
- package/scripts/lib/utils.js +380 -0
- package/scripts/lib/verify-formatter.js +143 -0
- package/scripts/lib/workflow-state.js +249 -0
- package/scripts/onboard.js +363 -0
- package/scripts/quarterly-report.js +692 -0
- package/scripts/setup-package-manager.js +204 -0
- package/scripts/sync-upstream.js +391 -0
- package/scripts/test.js +108 -0
- package/scripts/tutorial-runner.js +351 -0
- package/scripts/validate-all.js +201 -0
- package/scripts/verifiers/agents.js +245 -0
- package/scripts/verifiers/config.js +186 -0
- package/scripts/verifiers/environment.js +123 -0
- package/scripts/verifiers/hooks.js +188 -0
- package/scripts/verifiers/index.js +38 -0
- package/scripts/verifiers/persistence.js +140 -0
- package/scripts/verifiers/plugin.js +215 -0
- package/scripts/verifiers/skills.js +209 -0
- package/scripts/verify-setup.js +164 -0
- package/skills/INDEX.md +157 -0
- package/skills/backend-patterns/SKILL.md +586 -0
- package/skills/backend-patterns/catalyst-patterns.md +128 -0
- package/skills/bigquery-patterns/SKILL.md +27 -0
- package/skills/bigquery-patterns/performance-optimization.md +518 -0
- package/skills/bigquery-patterns/query-patterns.md +372 -0
- package/skills/bigquery-patterns/schema-design.md +78 -0
- package/skills/cloudstream-project-template/SKILL.md +20 -0
- package/skills/cloudstream-project-template/structure.md +65 -0
- package/skills/coding-standards/SKILL.md +524 -0
- package/skills/coding-standards/deluge-standards.md +83 -0
- package/skills/compliance-patterns/SKILL.md +28 -0
- package/skills/compliance-patterns/hipaa/audit-requirements.md +251 -0
- package/skills/compliance-patterns/hipaa/baa-process.md +298 -0
- package/skills/compliance-patterns/hipaa/data-archival-strategy.md +387 -0
- package/skills/compliance-patterns/hipaa/phi-handling.md +52 -0
- package/skills/compliance-patterns/pci-dss/saq-a-requirements.md +307 -0
- package/skills/compliance-patterns/pci-dss/tokenization-patterns.md +382 -0
- package/skills/compliance-patterns/pci-dss/zoho-checkout-patterns.md +56 -0
- package/skills/compliance-patterns/soc2/access-controls.md +344 -0
- package/skills/compliance-patterns/soc2/audit-logging.md +458 -0
- package/skills/compliance-patterns/soc2/change-management.md +403 -0
- package/skills/compliance-patterns/soc2/deluge-execution-logging.md +407 -0
- package/skills/consultancy-workflows/SKILL.md +19 -0
- package/skills/consultancy-workflows/client-isolation.md +21 -0
- package/skills/consultancy-workflows/documentation-automation.md +454 -0
- package/skills/consultancy-workflows/handoff-procedures.md +257 -0
- package/skills/consultancy-workflows/knowledge-capture.md +513 -0
- package/skills/consultancy-workflows/time-tracking.md +26 -0
- package/skills/continuous-learning/SKILL.md +84 -0
- package/skills/continuous-learning/config.json +18 -0
- package/skills/continuous-learning/evaluate-session.sh +60 -0
- package/skills/continuous-learning-v2/SKILL.md +126 -0
- package/skills/continuous-learning-v2/config.json +61 -0
- package/skills/frontend-patterns/SKILL.md +635 -0
- package/skills/frontend-patterns/zoho-widget-patterns.md +103 -0
- package/skills/gcp-data-engineering/SKILL.md +36 -0
- package/skills/gcp-data-engineering/bigquery/performance-optimization.md +337 -0
- package/skills/gcp-data-engineering/dataflow/error-handling.md +496 -0
- package/skills/gcp-data-engineering/dataflow/pipeline-patterns.md +444 -0
- package/skills/gcp-data-engineering/dbt/model-organization.md +63 -0
- package/skills/gcp-data-engineering/dbt/testing-patterns.md +503 -0
- package/skills/gcp-data-engineering/medallion-architecture/bronze-layer.md +60 -0
- package/skills/gcp-data-engineering/medallion-architecture/gold-layer.md +311 -0
- package/skills/gcp-data-engineering/medallion-architecture/layer-transitions.md +517 -0
- package/skills/gcp-data-engineering/medallion-architecture/silver-layer.md +305 -0
- package/skills/gcp-data-engineering/zoho-to-gcp/data-extraction.md +543 -0
- package/skills/gcp-data-engineering/zoho-to-gcp/real-time-vs-batch.md +337 -0
- package/skills/security-review/SKILL.md +498 -0
- package/skills/security-review/compliance-checklist.md +53 -0
- package/skills/strategic-compact/SKILL.md +67 -0
- package/skills/tdd-workflow/SKILL.md +413 -0
- package/skills/tdd-workflow/zoho-testing.md +124 -0
- package/skills/tutorial/SKILL.md +249 -0
- package/skills/tutorial/docs/ACCESSIBILITY.md +169 -0
- package/skills/tutorial/lessons/00-philosophy-and-workflow.md +198 -0
- package/skills/tutorial/lessons/01-basics.md +81 -0
- package/skills/tutorial/lessons/02-training.md +86 -0
- package/skills/tutorial/lessons/03-commands.md +109 -0
- package/skills/tutorial/lessons/04-workflows.md +115 -0
- package/skills/tutorial/lessons/05-compliance.md +116 -0
- package/skills/tutorial/lessons/06-zoho.md +121 -0
- package/skills/tutorial/lessons/07-hooks-system.md +277 -0
- package/skills/tutorial/lessons/08-mcp-servers.md +316 -0
- package/skills/tutorial/lessons/09-client-management.md +215 -0
- package/skills/tutorial/lessons/10-testing-e2e.md +260 -0
- package/skills/tutorial/lessons/11-skills-deep-dive.md +272 -0
- package/skills/tutorial/lessons/12-rules-system.md +326 -0
- package/skills/tutorial/lessons/13-golden-standard-graduation.md +213 -0
- package/skills/tutorial/lessons/14-fork-setup-and-sync.md +312 -0
- package/skills/tutorial/lessons/15-living-examples-system.md +221 -0
- package/skills/tutorial/tracks/accelerated/README.md +134 -0
- package/skills/tutorial/tracks/accelerated/assessment/checkpoint-1.md +161 -0
- package/skills/tutorial/tracks/accelerated/assessment/checkpoint-2.md +175 -0
- package/skills/tutorial/tracks/accelerated/day-1-core-concepts.md +234 -0
- package/skills/tutorial/tracks/accelerated/day-2-essential-commands.md +270 -0
- package/skills/tutorial/tracks/accelerated/day-3-workflow-mastery.md +305 -0
- package/skills/tutorial/tracks/accelerated/day-4-compliance-zoho.md +304 -0
- package/skills/tutorial/tracks/accelerated/day-5-hooks-skills.md +344 -0
- package/skills/tutorial/tracks/accelerated/day-6-client-testing.md +386 -0
- package/skills/tutorial/tracks/accelerated/day-7-graduation.md +369 -0
- package/skills/zoho-patterns/CHANGELOG.md +108 -0
- package/skills/zoho-patterns/SKILL.md +446 -0
- package/skills/zoho-patterns/analytics/dashboard-patterns.md +352 -0
- package/skills/zoho-patterns/analytics/zoho-to-bigquery-pipeline.md +427 -0
- package/skills/zoho-patterns/catalyst/appsail-deployment.md +349 -0
- package/skills/zoho-patterns/catalyst/context-close-patterns.md +354 -0
- package/skills/zoho-patterns/catalyst/cron-batch-processing.md +374 -0
- package/skills/zoho-patterns/catalyst/function-patterns.md +439 -0
- package/skills/zoho-patterns/creator/form-design.md +304 -0
- package/skills/zoho-patterns/creator/publish-api-patterns.md +313 -0
- package/skills/zoho-patterns/creator/widget-integration.md +306 -0
- package/skills/zoho-patterns/creator/workflow-automation.md +253 -0
- package/skills/zoho-patterns/deluge/api-patterns.md +468 -0
- package/skills/zoho-patterns/deluge/batch-processing.md +403 -0
- package/skills/zoho-patterns/deluge/cross-app-integration.md +356 -0
- package/skills/zoho-patterns/deluge/error-handling.md +423 -0
- package/skills/zoho-patterns/deluge/syntax-reference.md +65 -0
- package/skills/zoho-patterns/integration/cors-proxy-architecture.md +426 -0
- package/skills/zoho-patterns/integration/crm-books-native-sync.md +277 -0
- package/skills/zoho-patterns/integration/oauth-token-management.md +461 -0
- package/skills/zoho-patterns/integration/zoho-flow-patterns.md +334 -0
|
@@ -0,0 +1,403 @@
|
|
|
1
|
+
# Deluge Batch Processing
|
|
2
|
+
|
|
3
|
+
## Critical Constraints
|
|
4
|
+
|
|
5
|
+
> **5000 STATEMENT LIMIT:** Every Deluge execution (workflow, custom function, scheduled task) is limited to 5000 statements total. Loops, conditionals, and function calls all count. Plan accordingly.
|
|
6
|
+
|
|
7
|
+
> **getRecords MAX 200:** Each `getRecords` call returns at most 200 records. You MUST paginate to fetch more.
|
|
8
|
+
|
|
9
|
+
> **Subforms MAX 200 ROWS:** Subforms are capped at 200 rows. For larger datasets, use related child forms.
|
|
10
|
+
|
|
11
|
+
## Pagination Pattern (getRecords)
|
|
12
|
+
|
|
13
|
+
### Basic Pagination
|
|
14
|
+
|
|
15
|
+
```deluge
|
|
16
|
+
// Fetch all records using pagination
|
|
17
|
+
allRecords = List();
|
|
18
|
+
page = 1;
|
|
19
|
+
pageSize = 200;
|
|
20
|
+
hasMore = true;
|
|
21
|
+
|
|
22
|
+
while (hasMore)
|
|
23
|
+
{
|
|
24
|
+
batch = zoho.creator.getRecords("app", "All_Records_Report", "", page, pageSize);
|
|
25
|
+
|
|
26
|
+
if (batch.size() > 0)
|
|
27
|
+
{
|
|
28
|
+
allRecords.addAll(batch);
|
|
29
|
+
page = page + 1;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (batch.size() < pageSize)
|
|
33
|
+
{
|
|
34
|
+
hasMore = false;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Safety: prevent statement limit issues
|
|
38
|
+
if (page > 25) // 25 pages * 200 = 5000 records max per execution
|
|
39
|
+
{
|
|
40
|
+
info "Reached page limit, process remaining in next run";
|
|
41
|
+
hasMore = false;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
info "Total records fetched: " + allRecords.size();
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Pagination with Criteria
|
|
49
|
+
|
|
50
|
+
```deluge
|
|
51
|
+
// Paginate with filter criteria
|
|
52
|
+
criteria = "Status == \"Pending\" && Created_Date >= \"01-Jan-2024\"";
|
|
53
|
+
allPending = List();
|
|
54
|
+
page = 1;
|
|
55
|
+
|
|
56
|
+
while (true)
|
|
57
|
+
{
|
|
58
|
+
batch = zoho.creator.getRecords("app", "All_Orders", criteria, page, 200);
|
|
59
|
+
|
|
60
|
+
if (batch.size() == 0)
|
|
61
|
+
{
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
allPending.addAll(batch);
|
|
66
|
+
page = page + 1;
|
|
67
|
+
|
|
68
|
+
// Statement budget check (rough estimate)
|
|
69
|
+
if (page > 20)
|
|
70
|
+
{
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Statement Budget Estimation
|
|
77
|
+
|
|
78
|
+
| Operation | Approximate Cost |
|
|
79
|
+
|-----------|-----------------|
|
|
80
|
+
| Variable assignment | 1 statement |
|
|
81
|
+
| if/else check | 1 statement |
|
|
82
|
+
| for-each iteration | 1 per loop |
|
|
83
|
+
| getRecords call | 1 statement |
|
|
84
|
+
| createRecord call | 1 statement |
|
|
85
|
+
| invokeUrl call | 1 statement |
|
|
86
|
+
| Map/List operations | 1 per operation |
|
|
87
|
+
| String operations | 1 per operation |
|
|
88
|
+
|
|
89
|
+
### Budget Calculator
|
|
90
|
+
|
|
91
|
+
```deluge
|
|
92
|
+
// Example: Processing 200 records with 15 operations each
|
|
93
|
+
// Budget: 200 records * 15 ops = 3000 + pagination overhead (~50) = 3050
|
|
94
|
+
// Available: 5000 - 3050 = 1950 statements for error handling, logging
|
|
95
|
+
|
|
96
|
+
// Rule of thumb: Keep processing under 3500 statements
|
|
97
|
+
// Reserve 1500 for infrastructure (pagination, error handling, reporting)
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Chunking Large Operations
|
|
101
|
+
|
|
102
|
+
### Pattern 1: Process in Fixed Chunks
|
|
103
|
+
|
|
104
|
+
```deluge
|
|
105
|
+
// Process records in chunks to stay under statement limit
|
|
106
|
+
CHUNK_SIZE = 50; // Conservative: allows ~80 statements per record
|
|
107
|
+
allRecords = zoho.creator.getRecords("app", "Pending_Report", "", 1, 200);
|
|
108
|
+
|
|
109
|
+
processedCount = 0;
|
|
110
|
+
errorCount = 0;
|
|
111
|
+
chunkStart = 0;
|
|
112
|
+
|
|
113
|
+
while (chunkStart < allRecords.size() && chunkStart < CHUNK_SIZE)
|
|
114
|
+
{
|
|
115
|
+
record = allRecords.get(chunkStart);
|
|
116
|
+
|
|
117
|
+
try
|
|
118
|
+
{
|
|
119
|
+
// Process single record (keep operations minimal)
|
|
120
|
+
updateMap = Map();
|
|
121
|
+
updateMap.put("Processed_Date", zoho.currenttime);
|
|
122
|
+
updateMap.put("Status", "Processed");
|
|
123
|
+
updateMap.put("Calculated_Value", record.get("Quantity").toLong() * record.get("Rate").toDecimal());
|
|
124
|
+
|
|
125
|
+
zoho.creator.updateRecord("app", "Orders", record.get("ID").toLong(), updateMap);
|
|
126
|
+
processedCount = processedCount + 1;
|
|
127
|
+
}
|
|
128
|
+
catch (e)
|
|
129
|
+
{
|
|
130
|
+
errorCount = errorCount + 1;
|
|
131
|
+
info "Error processing record " + record.get("ID") + ": " + e.toString();
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
chunkStart = chunkStart + 1;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
info "Processed: " + processedCount + ", Errors: " + errorCount;
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Pattern 2: Marker-Based Chunking (Resume Between Runs)
|
|
141
|
+
|
|
142
|
+
```deluge
|
|
143
|
+
// Use a marker field to track progress across scheduled runs
|
|
144
|
+
criteria = "Batch_Processed == false";
|
|
145
|
+
batch = zoho.creator.getRecords("app", "All_Records", criteria, 1, 100);
|
|
146
|
+
|
|
147
|
+
processedIds = List();
|
|
148
|
+
|
|
149
|
+
for each record in batch
|
|
150
|
+
{
|
|
151
|
+
try
|
|
152
|
+
{
|
|
153
|
+
// Your processing logic here
|
|
154
|
+
result = processRecord(record);
|
|
155
|
+
|
|
156
|
+
// Mark as processed
|
|
157
|
+
zoho.creator.updateRecord("app", "Records", record.get("ID").toLong(), {
|
|
158
|
+
"Batch_Processed": true,
|
|
159
|
+
"Batch_Result": result,
|
|
160
|
+
"Batch_Date": zoho.currentdate
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
processedIds.add(record.get("ID"));
|
|
164
|
+
}
|
|
165
|
+
catch (e)
|
|
166
|
+
{
|
|
167
|
+
// Mark as failed (don't reprocess next run without review)
|
|
168
|
+
zoho.creator.updateRecord("app", "Records", record.get("ID").toLong(), {
|
|
169
|
+
"Batch_Processed": true,
|
|
170
|
+
"Batch_Result": "ERROR: " + e.toString(),
|
|
171
|
+
"Batch_Date": zoho.currentdate
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
info "Batch complete: " + processedIds.size() + " records processed";
|
|
177
|
+
// Next scheduled run will pick up remaining unprocessed records
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
## Tracking Progress
|
|
181
|
+
|
|
182
|
+
### Progress Tracking Form
|
|
183
|
+
|
|
184
|
+
Create a `Batch_Jobs` form with fields:
|
|
185
|
+
- Job_Name (Text)
|
|
186
|
+
- Total_Records (Number)
|
|
187
|
+
- Processed_Count (Number)
|
|
188
|
+
- Error_Count (Number)
|
|
189
|
+
- Status (Dropdown: Running, Completed, Failed, Partial)
|
|
190
|
+
- Started_At (DateTime)
|
|
191
|
+
- Completed_At (DateTime)
|
|
192
|
+
- Last_Error (Multi-line)
|
|
193
|
+
|
|
194
|
+
```deluge
|
|
195
|
+
// Initialize batch job tracking
|
|
196
|
+
jobMap = Map();
|
|
197
|
+
jobMap.put("Job_Name", "Monthly Invoice Generation");
|
|
198
|
+
jobMap.put("Total_Records", totalCount);
|
|
199
|
+
jobMap.put("Processed_Count", 0);
|
|
200
|
+
jobMap.put("Error_Count", 0);
|
|
201
|
+
jobMap.put("Status", "Running");
|
|
202
|
+
jobMap.put("Started_At", zoho.currenttime);
|
|
203
|
+
|
|
204
|
+
jobRecord = zoho.creator.createRecord("admin-app", "Batch_Jobs", jobMap);
|
|
205
|
+
jobId = jobRecord.get("ID").toLong();
|
|
206
|
+
|
|
207
|
+
// ... process records ...
|
|
208
|
+
|
|
209
|
+
// Update progress periodically (every 50 records)
|
|
210
|
+
if (processedCount % 50 == 0)
|
|
211
|
+
{
|
|
212
|
+
zoho.creator.updateRecord("admin-app", "Batch_Jobs", jobId, {
|
|
213
|
+
"Processed_Count": processedCount,
|
|
214
|
+
"Error_Count": errorCount
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Final update
|
|
219
|
+
zoho.creator.updateRecord("admin-app", "Batch_Jobs", jobId, {
|
|
220
|
+
"Processed_Count": processedCount,
|
|
221
|
+
"Error_Count": errorCount,
|
|
222
|
+
"Status": if(errorCount == 0, "Completed", "Partial"),
|
|
223
|
+
"Completed_At": zoho.currenttime
|
|
224
|
+
});
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
## Error Accumulation and Reporting
|
|
228
|
+
|
|
229
|
+
```deluge
|
|
230
|
+
// Collect errors during batch, report at end
|
|
231
|
+
errors = List();
|
|
232
|
+
warnings = List();
|
|
233
|
+
processed = 0;
|
|
234
|
+
|
|
235
|
+
records = zoho.creator.getRecords("app", "Report", "", 1, 200);
|
|
236
|
+
|
|
237
|
+
for each record in records
|
|
238
|
+
{
|
|
239
|
+
try
|
|
240
|
+
{
|
|
241
|
+
// Validate before processing
|
|
242
|
+
if (record.get("Email") == null || record.get("Email") == "")
|
|
243
|
+
{
|
|
244
|
+
warnings.add("Record " + record.get("ID") + ": Missing email, skipped");
|
|
245
|
+
continue;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// Process
|
|
249
|
+
result = doProcessing(record);
|
|
250
|
+
processed = processed + 1;
|
|
251
|
+
}
|
|
252
|
+
catch (e)
|
|
253
|
+
{
|
|
254
|
+
errors.add({
|
|
255
|
+
"record_id": record.get("ID"),
|
|
256
|
+
"error": e.toString(),
|
|
257
|
+
"timestamp": zoho.currenttime
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Generate report
|
|
263
|
+
report = "Batch Processing Report\n";
|
|
264
|
+
report = report + "========================\n";
|
|
265
|
+
report = report + "Total: " + records.size() + "\n";
|
|
266
|
+
report = report + "Processed: " + processed + "\n";
|
|
267
|
+
report = report + "Errors: " + errors.size() + "\n";
|
|
268
|
+
report = report + "Warnings: " + warnings.size() + "\n\n";
|
|
269
|
+
|
|
270
|
+
if (errors.size() > 0)
|
|
271
|
+
{
|
|
272
|
+
report = report + "ERRORS:\n";
|
|
273
|
+
for each err in errors
|
|
274
|
+
{
|
|
275
|
+
report = report + "- Record " + err.get("record_id") + ": " + err.get("error") + "\n";
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// Send report
|
|
280
|
+
sendmail [
|
|
281
|
+
from: zoho.adminuserid
|
|
282
|
+
to: "admin@company.com"
|
|
283
|
+
subject: "Batch Report: " + processed + "/" + records.size() + " processed"
|
|
284
|
+
message: report
|
|
285
|
+
];
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
## Scheduled Function Orchestration
|
|
289
|
+
|
|
290
|
+
For processing more than ~1000 records, split across multiple scheduled runs:
|
|
291
|
+
|
|
292
|
+
```deluge
|
|
293
|
+
// Master scheduler: runs every 15 minutes
|
|
294
|
+
// Checks if there's pending work and processes a chunk
|
|
295
|
+
|
|
296
|
+
// 1. Check batch status
|
|
297
|
+
statusRecords = zoho.creator.getRecords("admin-app", "Batch_Status", "Job_Name == \"daily_sync\"", 1, 1);
|
|
298
|
+
|
|
299
|
+
if (statusRecords.size() > 0)
|
|
300
|
+
{
|
|
301
|
+
status = statusRecords.get(0);
|
|
302
|
+
lastOffset = status.get("Last_Offset").toLong();
|
|
303
|
+
totalRecords = status.get("Total_Records").toLong();
|
|
304
|
+
|
|
305
|
+
if (lastOffset >= totalRecords)
|
|
306
|
+
{
|
|
307
|
+
info "All records processed. Resetting for tomorrow.";
|
|
308
|
+
zoho.creator.updateRecord("admin-app", "Batch_Status", status.get("ID").toLong(), {
|
|
309
|
+
"Last_Offset": 0,
|
|
310
|
+
"Status": "Idle"
|
|
311
|
+
});
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// 2. Process next chunk
|
|
316
|
+
CHUNK = 100;
|
|
317
|
+
page = (lastOffset / 200).toLong() + 1;
|
|
318
|
+
startInPage = lastOffset % 200;
|
|
319
|
+
|
|
320
|
+
records = zoho.creator.getRecords("app", "All_Records", "", page, 200);
|
|
321
|
+
processedInRun = 0;
|
|
322
|
+
|
|
323
|
+
idx = startInPage.toLong();
|
|
324
|
+
while (idx < records.size() && processedInRun < CHUNK)
|
|
325
|
+
{
|
|
326
|
+
record = records.get(idx);
|
|
327
|
+
processRecord(record);
|
|
328
|
+
processedInRun = processedInRun + 1;
|
|
329
|
+
idx = idx + 1;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// 3. Update offset
|
|
333
|
+
newOffset = lastOffset + processedInRun;
|
|
334
|
+
zoho.creator.updateRecord("admin-app", "Batch_Status", status.get("ID").toLong(), {
|
|
335
|
+
"Last_Offset": newOffset,
|
|
336
|
+
"Status": "In Progress",
|
|
337
|
+
"Last_Run": zoho.currenttime
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
info "Processed " + processedInRun + " records. Progress: " + newOffset + "/" + totalRecords;
|
|
341
|
+
}
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
## Parallel Processing Limitations
|
|
345
|
+
|
|
346
|
+
> **WARNING:** Deluge does NOT support parallel processing within a single execution. Each statement runs sequentially. For parallelism, use:
|
|
347
|
+
|
|
348
|
+
1. **Multiple scheduled functions** running at different intervals
|
|
349
|
+
2. **Catalyst Cron** with async operations (see catalyst/cron-batch-processing.md)
|
|
350
|
+
3. **Zoho Flow** for event-driven parallel processing
|
|
351
|
+
|
|
352
|
+
### Pseudo-Parallel: Multiple Scheduled Functions
|
|
353
|
+
|
|
354
|
+
```
|
|
355
|
+
Schedule 1 (every 15 min): Process records where ID % 3 == 0
|
|
356
|
+
Schedule 2 (every 15 min, offset 5 min): Process records where ID % 3 == 1
|
|
357
|
+
Schedule 3 (every 15 min, offset 10 min): Process records where ID % 3 == 2
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
```deluge
|
|
361
|
+
// Partition-based processing (Schedule 1)
|
|
362
|
+
criteria = "Mod(ID, 3) == 0 && Processed == false";
|
|
363
|
+
myPartition = zoho.creator.getRecords("app", "Records", criteria, 1, 100);
|
|
364
|
+
|
|
365
|
+
for each record in myPartition
|
|
366
|
+
{
|
|
367
|
+
processAndMark(record);
|
|
368
|
+
}
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
## Performance Tips
|
|
372
|
+
|
|
373
|
+
1. **Minimize getRecords calls** - Fetch 200 at once, not 1 at a time
|
|
374
|
+
2. **Batch updates** - Collect changes, apply in bulk where possible
|
|
375
|
+
3. **Pre-filter with criteria** - Don't fetch all records then filter in code
|
|
376
|
+
4. **Avoid nested loops** - O(n^2) statement consumption
|
|
377
|
+
5. **Use formula fields** - Offload calculations to form-level formulas
|
|
378
|
+
6. **Cache lookups** - Store repeated lookups in Maps
|
|
379
|
+
|
|
380
|
+
```deluge
|
|
381
|
+
// BAD: N+1 query pattern (fetches inside loop)
|
|
382
|
+
records = zoho.creator.getRecords("app", "Orders", "", 1, 200);
|
|
383
|
+
for each record in records
|
|
384
|
+
{
|
|
385
|
+
customer = zoho.creator.getRecords("app", "Customers", "ID == " + record.get("Customer_ID"), 1, 1);
|
|
386
|
+
// This makes 200+ API calls!
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
// GOOD: Pre-fetch and cache
|
|
390
|
+
customers = zoho.creator.getRecords("app", "Customers", "", 1, 200);
|
|
391
|
+
customerMap = Map();
|
|
392
|
+
for each cust in customers
|
|
393
|
+
{
|
|
394
|
+
customerMap.put(cust.get("ID").toString(), cust);
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
records = zoho.creator.getRecords("app", "Orders", "", 1, 200);
|
|
398
|
+
for each record in records
|
|
399
|
+
{
|
|
400
|
+
customer = customerMap.get(record.get("Customer_ID").toString());
|
|
401
|
+
// No additional API call needed!
|
|
402
|
+
}
|
|
403
|
+
```
|