[object Object]

A custom function that finishes in 2 seconds against 500 records and dies after 8 minutes against 50,000 is almost always the same three bugs. Loop shape matters more than logic.

Bug 1: searchRecords Without Pagination Bounds

zoho.crm.searchRecords returns up to 200 per call. If you call it once and assume you got everything, you get exactly 200. Always paginate explicitly:

page = 1;
all_records = list();
while(true)
{
    batch = zoho.crm.searchRecords("Leads", "(Status:equals:Open)", page, 200);
    if(batch.size() == 0) break;
    all_records.addAll(batch);
    page = page + 1;
}

Don’t use getRecords for large pulls — it does not support filter expressions and you’ll loop the entire module.

Bug 2: Updating Inside the Loop

A single zoho.crm.updateRecord per iteration is the most common kill switch. Each call is a network round-trip and counts against your API credit pool. Batch with bulkUpdate when the payload allows:

update_payload = list();
for each rec in all_records
{
    update_payload.add({"id": rec.get("id"), "Score": rec.get("Score") + 10});
}
zoho.crm.bulkUpdate("Leads", update_payload);

Bulk operations cap at 100 records per call, so chunk accordingly.

Bug 3: Map Mutations Inside Iterations

Modifying a map you’re iterating creates non-deterministic behavior in Deluge — particularly with nested for each loops. Build the result map outside the loop, assign once at the end.

Watch Your Execution Limits

Custom functions have a hard 5-minute wall and a 3,000 statement-per-invocation soft cap. If you’re approaching either, switch to a scheduled function that processes a chunk and re-schedules itself.

What to Do This Week

  1. Grep your org for any searchRecords call without an explicit while loop.
  2. Replace single-record updates inside loops with bulkUpdate chunks of 100.
  3. Add a statement counter (info log every 500 iterations) to your slowest function.
  4. Convert anything over 30s of expected runtime into a self-rescheduling job.
[object Object]
Share