Canary Routing
Route a small percentage of traffic to a new backend version while keeping the remainder on the stable path. When metrics confirm the canary is healthy, promote it to 100% with a single workflow publish — no service redeploy.
Typical scenario: Your team has deployed orders-service-v2 alongside the existing orders-service-v1. You want to send 10% of order API traffic to v2 to validate behavior before full rollout.
Prerequisites
- You are signed in to the Management UI as an admin or editor
- Two upstream services are reachable from the gateway:
- Stable:
https://orders-v1.internal - Canary:
https://orders-v2.internal
- Stable:
- A collection (e.g.
orders-api) and a proxy (e.g.GET /orders/{orderId}) exist and are published
How canary routing works in Zerq
The workflow uses a condition_node to evaluate a synthetic percentage condition. For each request, the condition evaluates whether a random value falls within the canary window (e.g. 0–10). If true, the request goes to the canary backend; otherwise it goes to the stable backend.
Both branches converge at a single response_node, so the client always receives one unified response.
Workflow overview
Step 1 — Open the workflow canvas
- Open Collections → orders-api.
- Select the
GET /orders/{orderId}proxy. - Click the Workflow tab.
Step 2 — Add the condition node
- Drag a Condition node from the palette and connect it from
http_trigger. - Name it
canary-split. - Set the condition expression:
{{math.random(100)}} < 10
This evaluates true for approximately 10% of requests and false for 90%.
To adjust the canary percentage, change 10 to any value from 1 to 100. To promote the canary to 100%, change the condition to always evaluate true, or replace both branches with a single stable backend call.
Step 3 — Add the canary backend node (true branch)
- Connect an
http_request_nodefrom the true output ofcanary-split. - Configure:
- Name:
call-v2-canary - Method:
GET - URL:
https://orders-v2.internal/orders/{{trigger.params.orderId}} - Headers: forward any required auth headers from
{{trigger.headers}}
- Name:
Step 4 — Add the stable backend node (false branch)
- Connect an
http_request_nodefrom the false output ofcanary-split. - Configure:
- Name:
call-v1-stable - Method:
GET - URL:
https://orders-v1.internal/orders/{{trigger.params.orderId}} - Headers: forward the same auth headers
- Name:
Step 5 — Converge at the response node
- Drag a Response node.
- Connect both
call-v2-canaryandcall-v1-stableto this node. - Configure the response to return the body from whichever branch ran:
Body: {{lastSuccessfulNode.response.body}}
Status: {{lastSuccessfulNode.response.status}}
lastSuccessfulNode resolves to whichever upstream node completed for this request path.
Step 6 — Save and publish
- Click Save on the canvas.
- Click Publish on the proxy.
Traffic will immediately begin splitting: approximately 10% to v2, 90% to v1.
Verify the split
Send 20 requests and observe distribution in logs:
for i in $(seq 1 20); do
curl -s -o /dev/null -w "%{http_code}\n" \
https://gateway.example.com/orders-api/orders/order-99 \
-H "X-Client-ID: <client-id>" \
-H "Authorization: Bearer <token>" \
-H "X-Profile-ID: <profile-id>"
done
Open Logs → Request Logs and filter by the orders-api collection. Check the upstream URL column — you should see roughly 2 out of 20 requests hitting orders-v2.internal and 18 hitting orders-v1.internal.
Promoting or rolling back
To promote canary to 100%:
- Open the
canary-splitcondition node. - Change the expression to
true(always true), or remove the condition and route directly tocall-v2-canary. - Save and publish.
To roll back immediately:
- Open the
canary-splitcondition node. - Change the expression to
false(always false), routing all traffic tocall-v1-stable. - Save and publish.
Both changes take effect immediately after publish with no gateway restart.
Advanced: route by header instead of percentage
For more deterministic testing (e.g. QA team always hits v2), use a header-based condition instead:
{{trigger.headers["X-Canary"]}} == "true"
Requests with X-Canary: true go to v2; all other requests go to v1.
Next steps
- Workflow Nodes — Condition — condition expression reference
- Workflow Templates — Canary — canary template walkthrough
- Request Logs — monitoring canary traffic
- Retry and Fallback — add resilience to the canary branch