Skip to content

Behaviors

A behavior tells a component how to handle items as they pass through. Set a behavior and your diagram becomes a working simulation: items arrive, wait in line, get filtered, retried, or split off down different paths.

ModeWhat it does
PassthroughSends items through unchanged (the default). With more than one outgoing line, it copies every item to every line.
FilterThrows out a percentage of items at random.
SplitSends each item to ONE of several outgoing lines. This is the real load balancer for parallel workers.
DelayHolds each item for a set time before passing it on.
RetryTries again when an item fails.
Circuit BreakerAfter too many failures, shuts off for a while, then carefully reopens.
BatchCollects items into a group, then releases the whole group at once.
ReplicateCopies every item to all outgoing lines (broadcast on purpose).

A component picks one mode. If you need two patterns together (say, throttle and retry), use two components in a row instead.

The single most common mix-up: passthrough with two outgoing lines does not split the work. It copies every item down both lines. If you want two workers to share the load, you need Split.

What you drawWhat the simulator doesWhat you probably wanted
Router (passthrough) → Worker A, Worker BBoth workers get every item. They do the same job twice and the rate doesn’t go up.Split — each item goes to one worker.
Router (split) → Worker A, Worker BEach item goes to one worker. With many items in flight, both workers run at the same time.Correct.
Event Bus (replicate) → Search, Cache, AnalyticsAll three see every event. Broadcast on purpose.Correct.

Quick rule: if both lines should do the same job on the same data (broadcast), use Replicate. If both lines should share the load (parallel workers), use Split. Passthrough with one line is fine; the copy behavior only matters once you wire a second line off the same component.

Queueing isn’t its own mode. Set Capacity on any component and it acts as a queue: items wait their turn, and items get dropped once the queue fills up. See Capacity & queueing below.

New here? Try a Lesson template to see each mode in action. Start with Pipeline Basics.

Each mode mapped to something a coffee shop actually does:

Queue the order line. Set capacity to 8 and service rate to 2. Eight customers can wait, two orders are made per step. Works on any mode.

Split the drink router. Mode = split, weight 70 on the espresso line, weight 30 on the blender line. 70% of orders go to espresso, 30% to the blender.

Delay the espresso machine. Wait time 300 ms to model brew time.

Throttle the espresso machine. Capacity 12 and service rate 3. Only three drinks made per step; up to twelve orders wait, the next gets dropped.

Filter the cancellations. Drop rate 15. About 15% of mobile orders get cancelled before they’re made.

Retry the blender. Failure rate 15, retries 2, wait between tries 1. The blender jams sometimes; the barista tries again.

Batch the tray. Group size 4. Four drinks collect before the tray goes out.

Replicate the order announcement. Wire “Order Complete” to both the pickup screen and the barista tracker. Every order shows up on both.

Circuit Breaker for espresso. Trip after 2 failures, shut down for 10 steps. If the machine fails twice, stop taking espresso orders for ten steps.

Passthrough the pickup counter. Nothing to set. Drinks go straight to the customer.

  1. Double-click a component to open it.
  2. Find Behavior in the Basic tab.
  3. Pick a mode and fill in the settings.

Just ask:

“Make the API filter out items where status isn’t active”

The AI picks the right mode and fills in the settings.

Components with a behavior set show a small lightning bolt on the canvas. Hover any component to see its mode and current settings.


The default. Items go through with no extra processing.

Use it for: Components that just hand items along — wrappers, simple stages, anything with one outgoing line.

Example: A “Router” that takes items and sends them to one place. No settings needed.

Watch out with two or more outgoing lines. A passthrough with multiple outgoing lines copies every item down every line. If you wanted those lines to share the work (two parallel workers), switch to Split. If you really did want every line to get a copy, use Replicate — same result, but it makes the intent obvious.


Two old modes used JavaScript expressions to mutate or route items. Both are gone: most users don’t write JavaScript, and the simulator doesn’t track item contents in a way that made either mode useful. For routing, use Split with weights on the outgoing lines. For labeling a data change, use the component’s description field.


Throws out a percentage of items at random. Filtered items are tracked separately from failures and don’t hurt the system health score, because the removal is on purpose.

SettingRangeDefault
Throw out0-100%0%

Use it for: Validation steps, screening, approval gates, anywhere you mean to drop some items. Filtered items show up in purple in the stats; real drops show up in red.

Examples:

  • 10% — a flaky network connection.
  • 50% — validation that rejects half of inputs.
  • 100% — fully block one path (handy when paired with Split for A/B testing).

Not a mode — a setting that any component can use. Set capacity and the component acts as a queue: items wait up to the limit, anything past that gets dropped, and a “QUEUE FULL” event fires. Find these on the Simulate tab.

SettingRangeDefault
CapacityFree-form (“100”, “10 GB”, “2 baristas”, “LP 80명”, “결정 30건”, “unlimited” / “무제한”)unlimited
Service rate1+auto
Queue typeStandard / FIFOStandard
Fallback queue (DLQ)On / OffOff

Capacity is a free-form text field. Write whatever fits (“100”, “10 baristas”, “1K rows”) — the simulator reads the leading number for the limit. Service rate is how many items the component handles at the same time (think: how many parallel workers). When the queue is full, the oldest waiting item is dropped. Standard queues are unordered and faster; FIFO processes in strict arrival order. Turn on the fallback queue to send failed or expired items there instead of dropping them silently.

These work on any mode. A passthrough with capacity 100 buffers 100 items, same as any other mode would.

Examples:

  • Message broker: capacity 100, service rate 5. Buffers bursts and drains steadily.
  • Single worker: capacity 20, service rate 1. One at a time, builds a backlog under load.
  • Fast consumer: capacity 50, service rate 10. High rate with overflow protection.

Sends each item down ONE of the outgoing lines. This is the real load balancer for parallel workers, and the right answer for routing items down different paths.

A single test item makes split look sequential, like it’s “taking turns.” That’s just because each item only walks one path. With many items in flight, every outgoing line runs in parallel.

Two ways to route:

  • Round-robin (default, all weights = 0): each item goes to the next line in order, then loops back.
  • Weighted: set a weight on each outgoing line and items split proportionally. The weights don’t have to sum to 100 — 70 / 30, 7 / 3, and 2 / 1 all give the same split.

Where to set weights: once a component is in Split mode, the Behavior panel shows a routing table that lists every outgoing line with a weight box. Edit the weights right there. (You can also click the connection line itself; it’s the same field.)

Use it for: Sharing work between parallel workers, sending some traffic one way and the rest another, main/backup routing, A/B traffic splits.

Examples:

  • A “Load Balancer” wired to three “Server” components. Round-robin sends item 1 to A, item 2 to B, item 3 to C, then loops.
  • 70/30 weights to send most traffic to a main server and the rest to a backup.

Watch out: putting weights on outgoing lines without setting the source to Split mode does nothing — the simulator still copies items down every line. If the source isn’t Split, the weights are ignored. The linter fixes this for AI-built designs; if you build by hand, set the mode yourself.


Holds each item for a set amount of time before passing it on.

SettingRangeDefault
Wait time10+ ms100ms

Use it for: Slow services, database queries, outside API calls, anything with real processing time.

Examples:

  • Database query: 200ms for a typical round-trip.
  • Outside API: 500ms for a third-party call.
  • Heavy work: 1000ms for CPU-bound steps.

Used to take a JavaScript rule like data.tier === "premium". Gone now. Use Split with weights instead — a 70/30 fork is weight: 70 on one outgoing line and weight: 30 on the other. That covers nearly every if/else routing case without needing code.


When an item fails, try again.

SettingRangeDefault
Try again up to1-10 times3
Wait between tries1-10 steps1
Fails ~% of the time0-100%30%
Give up after0+ mswait forever

“Fails ~% of the time” is how often each call fails on its first try. After a failure, the item waits (“wait between tries” × attempt number) before trying again. Once retries run out, the item is dropped (or sent to the fallback queue if you turned that on). “Give up after” sets a hard wait limit before treating an item as failed.

Use it for: Calls that occasionally fail and need another shot. Retry storms.

Examples:

  • Flaky service: failure 20%, retries 3, wait 2. Tries again with growing pauses (2, 4, 6 steps).
  • Aggressive: failure 50%, retries 5, wait 1. Lots of fast retries to stress the next step.
  • Conservative: failure 10%, retries 2, wait 5. Few retries, long pauses.

For rate limits, use Passthrough with a tight capacity and service rate. Both work on any mode, and together they do the same thing a dedicated rate-limit mode would: cap how much gets through per step and queue any extra.

SettingRangeNotes
Capacityany int ≥ 1Max queue depth; anything past this gets dropped.
Service rateany int ≥ 1Max items handled per step.

Use it for: API gateways, throttling, register limits, any token-bucket scenario. Set service rate to the rate you want; capacity covers short bursts.

Examples:

  • API gateway: capacity 30, service rate 10. Steady traffic flows through; spikes queue up and drop above 30 in flight.
  • Strict throttle: capacity 5, service rate 1. One per step, queue of 5 absorbs short bursts.

There used to be a dedicated Rate Limit mode. We dropped it because passthrough + capacity + service rate covers the same ground with one fewer mode for the AI to mix up.


Stops a chain reaction of failures by shutting off after too many errors.

SettingRangeDefault
Trip after this many failures1-203
Stay shut down for1-50 steps5
Fails ~% of the time0-100%20%
Give up after0+ mswait forever

The three states:

  1. Closed (normal): items pass through, failures get counted.
  2. Open (shut down): every item is dropped right away. Waits for the cooldown.
  3. Half-Open (testing): one test item gets through. If it works, the breaker closes and traffic resumes. If it fails, the breaker shuts down again. Waiting items don’t get dropped during the test.

Use it for: Protecting a service from a flood of bad calls when something downstream is failing. The same pattern as real circuit breakers like Hystrix or Resilience4j.

Examples:

  • Standard: trip at 3, cooldown 5, failure 20%. Shuts down after 3 failures, waits 5 steps, tests.
  • Sensitive: trip at 1, cooldown 10, failure 30%. Shuts down on the first failure, takes a long time to recover.
  • Tolerant: trip at 10, cooldown 3, failure 10%. Soaks up many failures before shutting down.

Collects items into a group, then releases the whole group at once.

SettingRangeDefault
Group size2-1003

Items pile up until the group is full, then they all leave together. After the batch component, the group splits back into individual items for the next step. So a batch of 3 arrives at the next component as 3 separate items, not 1.

Use it for: Batch jobs, bulk API calls, anything that benefits from grouping.

Examples:

  • Batch writer: group size 10. Saves 10 records to the database at once. The next component sees 10 individual records.
  • Aggregator: group size 5. Bundles incoming events before forwarding a summary.

See the Batch & Scale lesson template for batch + replicate together.


Copies every item to every outgoing line. Different from Split, which sends each item down ONE line. Replicate sends every item down EVERY line, so 1 IN becomes N OUT (where N is the outbound count).

Use it for side-effects only. At least one outbound should be a side-effect target: log, audit, metric, notification, cache write, telemetry, webhook, event bus. Every item legitimately goes to all of them because each target consumes the item independently.

Examples that work:

  • A “Message Bus” wired to three subscribers (each subscriber needs the message). Every message reaches all three.
  • A change feed wired to search index, cache invalidator, and analytics — each system sees every change.
  • An order completion event wired to user notification, audit log, and stats aggregator.

Don’t use replicate when each item should pick ONE path. If your outbounds are primary consumers and the item belongs to exactly one of them (a drink goes to ONE customer who sits OR leaves; an order routes to cafe pickup OR drive-thru pickup; a request hits ONE shard), that’s Split, not Replicate. Replicate-to-consumer-paths inflates OUT counts and makes the canvas lie about how many items were actually served.

Quick test: if the two outbound paths reach DIFFERENT exits and never merge, each item should pick ONE → use Split. If at least one outbound is a side-effect target where every item legitimately needs to go → Replicate.


Each component gets one mode, so combine patterns by chaining components.

[Throttle: Passthrough cap+rate] -> [Retry] -> [Circuit Breaker] -> [Service]

A real resilience stack: limit traffic at the front, retry temporary failures, shut things off if the service is down. Each component does one job.

Other useful combos:

[Filter] -> [Batch] -> [Database]

Reject bad inputs, batch the rest, write the batch.

[Split (weighted)] -> [Worker A]
-> [Worker B]

A 70/30 fork: weight 70 on the line to Worker A, weight 30 on the line to Worker B.