Workflow and Automation Engines

By the Syncfusion DevTutorials team · Last updated

Let each tenant automate its own work with trigger, condition and action rules, then stop the rule that triggers itself, the retry that pages someone twice and the import that takes every worker.

When a Ticket Is Urgent, Page the Lead

Acme Retail wants a simple thing: when a ticket becomes urgent, page the on-call lead. Contoso wants every imported ticket tagged. Fabrikam wants tickets closed after 7 quiet days. Fifty tenants, hundreds of different wishes, and none of them should need a Northwind developer.

So Northwind ships an automation engine: customers build their own rules in the product, and shared workers run them. That is powerful, and it brings three new ways to fail: a rule can trigger itself forever, a retry can do something twice, and one tenant's rules can keep everyone else's waiting.

The main idea: store rules as tenant data (trigger, condition, action), run actions from a queue, record what caused each change so rules cannot loop, give every action an idempotency key so retries are safe, and cap how many workers one tenant can use.

TL;DR

  • A rule is data: when (trigger event), if (condition), then (action). Each tenant has its own rules.
  • The engine listens to events, finds the tenant's matching rules and puts actions on a queue. Workers run them.
  • A rule whose action fires its own trigger loops forever. Record who caused each change and stop chains with a loop guard.
  • Workers retry failed actions. Send an idempotency key with each action so a retry never does the work twice.
  • Give each tenant a limit on shared workers, so a bulk import cannot block everyone.

A Real-World Example

A help desk customer adds a rule: "when a ticket is updated, add the note We are looking into it". Adding a note updates the ticket. Within a minute, one ticket has 40,000 notes, the customer's email notifications have gone out 40,000 times, and the shared workers are busy with nothing else. The vendor adds an emergency kill switch that night, and a loop guard the next week.

What You Will Learn

  1. How rules are stored and run.
  2. Why actions run on a queue.
  3. How a rule triggers itself, and how a loop guard stops it.
  4. How idempotency keys make retries safe.
  5. How per-tenant limits keep shared workers fair.

Rules Are Tenant Data

Events find this tenant's rules; true conditions put actions on a queue. The loop guard and per-tenant limits sit in the path, not in each rule.

A rule is a row, not code: (tenant, trigger, condition, action, enabled). This is the same idea as custom fields in Lesson 4: the product reads the tenant's definitions at run time, so 50 tenants can have 50 different setups on one codebase.

Keep conditions to a small, safe language: compare fields, check a value changed, combine with AND and OR. Never run customer-written code inside your workers without a real sandbox, time limits and memory limits.

Loops: a Rule That Triggers Itself

Loops also hide across rules: rule A updates a field that triggers rule B, which triggers rule A. A depth limit catches those too.

Every automated change should carry its cause: which rule, which event, how deep in the chain. Without that, the engine cannot tell an agent's edit from its own echo. Keep a per-tenant kill switch as well, so support can stop a runaway rule in seconds.

Retries Without Doing It Twice

Actions call other systems: a pager, an email service, a customer's webhook. Calls fail, and replies get lost. Workers must retry, and the other side must be able to say "I have already done that".

The key must be the same on every try of the same action: build it from the tenant, the record, the rule and the event, never from the time or a random number.

One Tenant Must Not Take Every Worker

This is the noisy-neighbour problem from Lesson 3, in a new place. The same tools apply: per-tenant concurrency limits, fair queues, and a dedicated pool for a whale tenant that automates heavily.

Try It: Make the Rule Engine Safe to Share

  1. With no fixes, follow Ana's single change. How many rule runs does it cause?
  2. Turn on the loop guard. Then look at the pages: why does the lead get some pages twice?
  3. Turn on idempotency keys, then the per-tenant limit. What happens to Contoso's import time?

Pass rule: at most 10 rule runs for one change, all 20 urgent tickets paged exactly once, other tenants wait at most 1 s, and Contoso's import still finishes within 120 s.

Scheduled rules ("close tickets after 7 quiet days") need a durable timer: store the due time in the database and let a scheduler pick up due rows. An in-memory timer is lost when the server restarts. The help desk case study uses this for SLA timers.

Check Yourself

Common mistakes

MistakeWrongCorrectWhy it happens
No loop guardA rule updates the record that triggers itSkip changes made by the same rule; cap the chain depthEach rule looks fine on its own
Random idempotency keysA new key on each retryKey from tenant, record, rule and eventThe key is generated where the call is made
Inline actionsThe save waits for the email serviceQueue the actionIt is less code at first
Shared, unlimited workersOne import uses every workerPer-tenant limits or fair queuesTests run with one tenant
No kill switchEngineers edit the database to stop a ruleA per-tenant "pause automations" switchNobody plans for the first runaway rule

Practice

What to Remember

  • Rules are tenant data: trigger, condition, action.
  • Run actions from a queue, with retries.
  • Record the cause of every automated change, and guard against loops.
  • Use stable idempotency keys so retries never repeat work.
  • Limit each tenant's share of the workers.

Further Reading

Next: Integrations: Public API and Webhooks. Customers connect Northwind to their own systems. You deliver every webhook, sign it, and stop one broken endpoint from slowing everyone else.