Canary deployments
A canary deployment runs a new build next to your stable build and sends it a share of new sessions, so you can see how it behaves before everyone gets it. It is available on Advanced and Ultimate plans. Free, Budget, and Budget+ projects get 403 plan_feature_unavailable.
How a canary uses your pods
The canary takes a whole number of your plan's pods, and the share of new sessions it receives equals its share of the pods. Advanced has 3 pods, so a canary gets 1 or 2 of them (33 % or 67 % of new sessions). Ultimate has 8, so a canary gets anything from 1 to 7 (12.5 % steps). The stable build and the canary together never use more pods than your plan allows, which means the stable build runs on fewer pods while a canary is active. Sessions already in progress are never moved.
Only one canary can run per project at a time, and its build must have passed validation.
Routing
You choose how new sessions are split when you start the canary.
- Round robin (default). Sessions are handed out in turn, so the share is exact and the canary sessions are spread out. With 1 of 3 pods, every third session goes to the canary: of the next 30 sessions, 10 run on the canary and 20 on the stable build.
- Customer context. You name a top-level field of the
customerContextyour client sends when it starts a session, for exampleuser_id. The same value always lands on the same build as long as the pod split stays the same, so one caller does not flip between versions from call to call. The value can be a string or a number of up to 256 characters, and the whole context can be up to 4 KB. A session without that field, or with a value that does not fit, falls back to round robin. Only a hash of the value is used for routing; the value itself is not stored.
The field name takes 1 to 64 letters, digits, underscores or dashes. You can change the pod count or the routing mode while the canary runs.
Auto-abort
Auto-abort is on by default. The platform checks every active canary about twice a minute. Once at least min_sessions (default 20) canary sessions have ended since the canary started, it aborts the canary if more than max_failure_rate_pct (default 20) percent of them failed. A session counts as failed when its status is failed or it ended with an agent crash, the same rule the metrics views use.
An auto-abort behaves like a manual abort: new sessions go back to the stable build and calls in progress on the canary finish. The deployment is marked as auto-aborted. You can change the thresholds at any time, or switch auto-abort off and decide yourself.
Promote and abort
- Promote makes the canary build the stable build. All new sessions go to it, it gets the full pod count of your plan, and the previous stable build drains: its calls in progress finish, as described in Rollout modes.
- Abort stops sending new sessions to the canary. Calls in progress on it finish, and the stable build gets the full pod count back.
While a canary is active a normal deploy is refused with canary_active. Promote or abort first.
See which build handled each session
Every session records the build it ran on. In the dashboard, the project's Deployments page shows the stable and canary builds side by side, with a table of sessions, failed sessions, failure rate and the most common failure reasons per build, over the last hour, 24 hours or 7 days. The sessions list has a Deploymentfilter and column, and a session's detail page links to the deployment it ran on. The same numbers are available from the CLI and the API below.
Dashboard
- Upload a build and wait until it is validated.
- Open Deployments for the project and choose Start canary.
- Pick the build, the number of pods (the share of sessions is shown next to it), the routing and the auto-abort thresholds.
- Watch the per-build table. Choose Promote when the canary looks good, or Abort canary when it does not.
CLI
Needs @voicethere/cli. See CLI reference for login and project selection.
# Upload a build, then run it on 1 pod voicethere deploy --build-id <id> --canary-pods 1 --wait # Route by a customer context field instead of by share voicethere deploy --build-id <id> --canary-pods 1 \ --routing customer-context --context-field user_id voicethere canary status voicethere canary set --pods 2 voicethere canary auto-abort --rate 10 --min-sessions 50 voicethere canary auto-abort --off voicethere canary promote --yes voicethere canary abort --yes # Sessions, failures and failure rate per build voicethere deployments metrics --since 24h
--since takes values like 30m, 24h or 7d. A canary deploy needs --build-id and the default drain mode. promote and abort ask for confirmation unless you pass --yes, which is required without a terminal.
API
All routes are under /api/v1 and use the same authentication as the rest of the Control plane API. The project is taken from the path and your credentials.
| Route | Body | What it does |
|---|---|---|
GET /projects/:projectId/canary | none | Current canary, the pod options for your plan and the live state. canary is null when none is active. |
POST /projects/:projectId/canary | { "build_id": "<uuid>", "canary_pods": 1 } | Starts a canary (202). Optional fields: auto_abort_enabled, max_failure_rate_pct, min_sessions, routing_mode (round_robin or customer_context), routing_context_field. |
PATCH /projects/:projectId/canary | { "canary_pods": 2, "max_failure_rate_pct": 10 } | Changes any of the fields above on the running canary. |
POST /projects/:projectId/canary/promote | none | Promotes the canary. |
POST /projects/:projectId/canary/abort | none | Aborts the canary. |
POST /deployments | { "project_id": "<uuid>", "build_id": "<uuid>", "canary_pods": 1 } | The same as starting a canary, in the shape of a deploy request. Accepts the optional canary fields too. |
GET /projects/:projectId/deployments/metrics?from=&to= | none | Sessions, failed, failure rate and top failure reasons per build. from and to are ISO 8601 timestamps. The default is the last 24 hours and the longest range is 31 days. |
curl -X POST "https://app.voicethere.io/api/v1/projects/$PROJECT_ID/canary" \
-H "Authorization: Bearer $VOICETHERE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"build_id": "11111111-aaaa-4bbb-8ccc-000000000001",
"canary_pods": 1,
"routing_mode": "customer_context",
"routing_context_field": "user_id",
"max_failure_rate_pct": 15,
"min_sessions": 30
}'Client SDK
With routing_mode: customer_context, pass the field you named when you start the session. The result tells you which build the session runs on.
import { startSession } from "@voicethere/client/browser";
const provision = await startSession({
apiBase: "https://sessions.example/v1",
projectId,
headers: { Authorization: `Bearer ${apiKey}` },
customerContext: { user_id: "u_123" },
});
if (provision.ok) {
console.log(provision.buildId); // build this session runs on, or null
}customerContext must be a plain object of at most 4096 bytes as JSON. A larger one is rejected with customer_context_too_large before the session starts.
Limits and errors
| Code | HTTP | Meaning and what to do |
|---|---|---|
plan_feature_unavailable | 403 | Your plan has no canary deployments. Upgrade to Advanced or Ultimate. |
invalid_canary_pods | 400 | The pod count must be a whole number from 1 to your plan's pods minus one (1 to 2 on Advanced, 1 to 7 on Ultimate). |
invalid_routing_context_field | 400 | Customer context routing needs a field name of 1 to 64 letters, digits, underscores or dashes, and a field name is not allowed with round robin. |
canary_already_active | 409 | The project already has a canary. Promote or abort it first. |
canary_active | 409 | A normal deploy was refused because a canary is active. Promote or abort it, then deploy. |
canary_not_active | 404 | Promote, abort or change was called but no canary is running. |
customer_context_too_large | 400 | The session start carried a customer_context over 4096 bytes. Send a smaller object. |