Trigger Loop Prevention¶
Overview¶
When an event-driven trigger fires a function that modifies records in the same collection, it can create an infinite loop — the function's write fires the trigger again, which fires the function again, and so on. Centrali prevents this with three layers of protection: static analysis, runtime detection, and rate limiting.
Trigger loop prevention applies to event-driven triggers only. Scheduled triggers and HTTP triggers are not affected.
Layer 1: Static Analysis¶
When you create or update an event-driven trigger, Centrali scans the linked function's code for SDK calls that would re-fire the trigger.
For example, if you create a trigger on record_updated for the orders collection, and the function calls api.updateRecord('orders', ...), that's a self-loop — the update would fire the trigger again.
What's checked¶
The analyzer maps each event type to the SDK methods that would produce that event:
| Event Type | SDK Methods That Would Re-Fire |
|---|---|
record_created | createRecord, upsertRecord, batchCreateRecords, bulkCreateRecords |
record_updated | updateRecord, upsertRecord, incrementField, decrementField, batchUpdateRecords, bulkUpdateRecords |
record_deleted | deleteRecord, batchDeleteRecords, bulkDeleteRecords |
records_bulk_created | bulkCreateRecords |
records_bulk_updated | bulkUpdateRecords |
records_bulk_deleted | bulkDeleteRecords |
record_restored and record_expired events cannot be triggered by SDK methods, so they are not checked.
When it runs¶
Static analysis runs when you:
- Create an event-driven trigger
- Update a trigger's function, event type, or collection
- Re-enable a paused trigger
- Update the code of a function that has linked triggers
What happens if a loop is detected¶
At trigger creation, the console shows a "Trigger loop detected" dialog listing the conflicting SDK calls. You can go back and fix the function, or choose a different collection.
If a loop is detected when you update function code, the system auto-pauses any affected triggers to prevent the loop from firing.
Cross-collection writes are allowed¶
Static analysis only blocks writes to the same collection the trigger listens on. A trigger on orders.record_updated that calls api.createRecord('audit_logs', ...) is fine — different collections don't create loops.
Layer 2: Runtime Detection¶
Even if static analysis doesn't catch a loop (for example, if the collection is determined dynamically at runtime), a second layer of protection exists.
Every record event carries a sourceTriggerId that tracks which trigger started the chain. Before firing a trigger, the system checks: if the event's sourceTriggerId matches the trigger's own ID, the trigger is skipped.
This propagates through all record operations — single, batch, and bulk — so indirect loops through multiple function calls are also caught.
Layer 3: Rate Limiting¶
As a final safety net, each event-driven trigger has a per-trigger rate limit.
| Setting | Default |
|---|---|
| Max executions | 500 per 60 seconds |
| Storage | Redis sliding window |
If a trigger exceeds the rate limit, it is automatically paused and all further executions are skipped until an admin re-enables it.
If Redis is unavailable, the rate limiter fails open (allows execution) to avoid blocking legitimate triggers.
Auto-Pause¶
Triggers are automatically paused (disabled) in two situations:
- Rate limit exceeded — the trigger fired too many times in the rate window
- Function code update — the linked function was updated and now contains a self-loop
When a trigger is auto-paused, it appears as paused in the console with the reason recorded. You can re-enable it after fixing the underlying issue.
What's Covered¶
All record mutation paths propagate loop detection:
Single operations: createRecord, updateRecord, deleteRecord, incrementField, decrementField
Batch operations: batchCreateRecords, batchUpdateRecords, batchDeleteRecords — these fire individual events per record
Bulk operations: bulkCreateRecords, bulkUpdateRecords, bulkDeleteRecords — these fire a single aggregate event