Back to Copilotkit

Deploy and operate

showcase/shell-docs/src/content/docs/channels/deploy-and-operate.mdx

1.64.26.4 KB
Original Source

A managed Channel is a long-running worker with an outbound realtime connection. It is not a serverless request handler. Deploy it like a queue consumer or WebSocket worker.

Use the tested runtime pair

bash
npm install --save-exact @copilotkit/[email protected] @copilotkit/[email protected]

Run Node.js 22 or later. The managed launcher relies on the global WebSocket available in Node.js 22+.

Upgrade Channels and Runtime together, then run the same real-provider smoke test used for the initial quickstart.

Settle before reporting ready

Creating the Node listener starts the managed connection — a declared Channel connects because it was declared, with no start call to forget. Await ready() to observe that activation settling, then inspect status():

ts
const channels = listener.channels;

await channels.ready({ timeoutMs: 30_000 });

const initial = channels.status();
if (initial.overall !== "online") {
  throw new Error(`Channels not online: ${JSON.stringify(initial)}`);
}

ready() can resolve in setup_required; it means activation settled, not that delivery is healthy. Treat only status().overall === "online" as a healthy connected activation.

The runtime status values are:

Runtime statusMeaning
connectingActivation has not settled
onlineThe managed connection is healthy and can claim delivery invitations
setup_requiredThe Intelligence provider setup is incomplete
reconnectingThe gateway connection dropped and is retrying
errorActivation failed, or reconnect give-up (~60s default) marked the session not-sendable
stoppedThe Channels control was stopped

Treat post-online error carefully: after reconnect give-up the client marks error while Phoenix keeps retrying underneath. A successful rejoin restores online without a process restart. Activation-time error (bad key, unreachable gateway, config) is different — fix configuration and restart the worker.

The Intelligence UI translates provider and runtime details into its own operator-facing states such as Waiting for runtime, Conflict, Offline, Delivery failing, and Online.

Expose liveness and readiness separately

  • Liveness answers whether the Node process and event loop are running.
  • Readiness answers whether channels.status().overall is online.

Do not restart immediately for a short reconnecting episode; the realtime client owns bounded reconnect and rejoin (default reconnect give-up window is about 60 seconds, then status becomes error while retries continue). Alert on error; restart only when your own outage budget is exceeded or activation failed before ever going online.

Poll status() from your health endpoint or monitoring loop. Do not cache the startup result forever because an online session can later become reconnecting or error.

Shut down cleanly

Register signal handlers before creating the listener, not just before ready(). Creating it begins activation, so a signal that arrives during the connect window must already have somewhere to land — otherwise it hits Node's default handler and leaves a live gateway session behind:

ts
let teardown: (() => Promise<void>) | undefined;
const shutdown = async () => {
  await teardown?.();
};

process.once("SIGINT", shutdown);
process.once("SIGTERM", shutdown);

const listener = createCopilotNodeListener({ runtime });
const server = createServer(listener);
teardown = async () => {
  await listener.channels.stop();
  if (server.listening) server.close();
};

await listener.channels.ready({ timeoutMs: 30_000 });

Give the worker enough termination grace to stop its managed sessions. Avoid cutting power before channels.stop() has released ownership when a graceful shutdown is possible.

Store and rotate secrets

Keep these server-side:

dotenv
INTELLIGENCE_API_KEY=<project-runtime-key>
CHANNEL_CODE=<exact-intelligence-code>

# Optional paired overrides for self-hosted or non-production Intelligence:
# INTELLIGENCE_API_URL=https://intelligence.example.com
# INTELLIGENCE_GATEWAY_WS_URL=wss://realtime.intelligence.example.com

Hosted Intelligence supplies the managed endpoints by default. For a self-hosted or non-production deployment, override both bases together. Do not derive one from the other or append /api, /socket, /runner, /client, or /channels.

Provider credentials stay in Intelligence. The runner should not contain Slack tokens or the Teams client secret. Rotate the project runtime key through your secret manager, restart the listener with the new value, and verify it returns to Online.

Bound active replicas

Intelligence offers each prepared delivery to connected Runtimes that declare the matching Channel. One Runtime claims that delivery; other replicas can claim different deliveries at the same time.

Run the same build and Channel declarations on every replica. Set maxConcurrentDeliveries to a bound each process can sustain. A full Runtime declines an invitation before it claims the delivery, which leaves another eligible replica free to claim it.

Observe the full delivery path

At minimum, record:

  • startup and the first non-online status
  • transitions to reconnecting, error, and back to online
  • Channel Code and provider, without credentials
  • application tool errors and their idempotency ids
  • message.eventId, message.turnId, and message.deliveryId for correlation
  • thread.postFile() failures

Do not log message bodies, hydrated files, API keys, Slack tokens, Teams secrets, or raw provider payloads by default.

Release checklist

  1. Build and typecheck the runner on Node.js 22.
  2. Confirm the exact package pair is in the lockfile.
  3. Start the intended replica set and wait for each listener to report online.
  4. Send a real provider message and verify a reply.
  5. Exercise one tool, one rich message, and one interaction.
  6. Restart with a pending approval and confirm your persistence promise.
  7. Test a brief network drop and observe reconnecting recovery.
  8. Send concurrent messages and verify replicas claim distinct deliveries within their local bounds.
  9. Send SIGTERM and confirm graceful shutdown.

Use the Intelligence walkthrough for control-plane statuses and persistence and scaling for restart-safe application state.