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 customerContext your client sends when it starts a session, for example user_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

  1. Upload a build and wait until it is validated.
  2. Open Deployments for the project and choose Start canary.
  3. Pick the build, the number of pods (the share of sessions is shown next to it), the routing and the auto-abort thresholds.
  4. 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.

RouteBodyWhat it does
GET /projects/:projectId/canarynoneCurrent 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/promotenonePromotes the canary.
POST /projects/:projectId/canary/abortnoneAborts 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=noneSessions, 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

CodeHTTPMeaning and what to do
plan_feature_unavailable403Your plan has no canary deployments. Upgrade to Advanced or Ultimate.
invalid_canary_pods400The 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_field400Customer 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_active409The project already has a canary. Promote or abort it first.
canary_active409A normal deploy was refused because a canary is active. Promote or abort it, then deploy.
canary_not_active404Promote, abort or change was called but no canary is running.
customer_context_too_large400The session start carried a customer_context over 4096 bytes. Send a smaller object.

← All documentation