Lo mejor para: Desarrolladores de plataformas, generadores de SaaS, cualquier implementación que sirva más de un puñado de usuarios simultáneos.
Conceptos principales
Antes de elegir un patrón, comprenda tres dimensiones de escalado:

Patrones de aislamiento de sesión
Patrón 1: CLI aislada por usuario
Cada usuario obtiene su propia instancia del servidor de la CLI. Aislamiento más seguro: las sesiones, la memoria y los procesos de un usuario están completamente separados.

Cuándo usar:
- SaaS multiinquilino donde el aislamiento de datos es crítico
- Usuarios con credenciales de autenticación diferentes
- Requisitos de cumplimiento (SOC 2, HIPAA)
// CLI pool manager — one CLI per user
class CLIPool {
private instances = new Map<string, { client: CopilotClient; port: number }>();
private nextPort = 5000;
async getClientForUser(userId: string, token?: string): Promise<CopilotClient> {
if (this.instances.has(userId)) {
return this.instances.get(userId)!.client;
}
const port = this.nextPort++;
// Spawn a dedicated CLI for this user
await spawnCLI(port, token);
const client = new CopilotClient({
cliUrl: `localhost:${port}`,
});
this.instances.set(userId, { client, port });
return client;
}
async releaseUser(userId: string): Promise<void> {
const instance = this.instances.get(userId);
if (instance) {
await instance.client.stop();
this.instances.delete(userId);
}
}
}
Patrón 2: CLI compartida con aislamiento de sesión
Varios usuarios comparten un servidor de la CLI, pero tienen sesiones aisladas a través de identificadores de sesión únicos. Consume menos recursos, pero ofrece un aislamiento más débil.

Cuándo usar:
- Herramientas internas con usuarios de confianza
- Entornos con restricción de recursos
- Requisitos de aislamiento más bajos
const sharedClient = new CopilotClient({
cliUrl: "localhost:4321",
});
// Enforce session isolation through naming conventions
function getSessionId(userId: string, purpose: string): string {
return `${userId}-${purpose}-${Date.now()}`;
}
// Access control: ensure users can only access their own sessions
async function resumeSessionWithAuth(
sessionId: string,
currentUserId: string
): Promise<Session> {
const [sessionUserId] = sessionId.split("-");
if (sessionUserId !== currentUserId) {
throw new Error("Access denied: session belongs to another user");
}
return sharedClient.resumeSession(sessionId);
}
Patrón 3: sesiones compartidas (colaborativas)
Varios usuarios interactúan con la misma sesión, como un salón de chat compartido con Copilot.

Cuándo usar:
- Herramientas de colaboración en equipo
- Sesiones de revisión de código compartido
- Asistentes de programación de pares
⚠️Importante: El SDK no proporciona bloqueo de sesión integrado. Debe serializar el acceso para evitar escrituras simultáneas en la misma sesión.
import Redis from "ioredis";
const redis = new Redis();
async function withSessionLock<T>(
sessionId: string,
fn: () => Promise<T>,
timeoutSec = 300
): Promise<T> {
const lockKey = `session-lock:${sessionId}`;
const lockId = crypto.randomUUID();
// Acquire lock
const acquired = await redis.set(lockKey, lockId, "NX", "EX", timeoutSec);
if (!acquired) {
throw new Error("Session is in use by another user");
}
try {
return await fn();
} finally {
// Release lock (only if we still own it)
const currentLock = await redis.get(lockKey);
if (currentLock === lockId) {
await redis.del(lockKey);
}
}
}
// Usage: serialize access to shared session
app.post("/team-chat", authMiddleware, async (req, res) => {
const result = await withSessionLock("team-project-review", async () => {
const session = await client.resumeSession("team-project-review");
return session.sendAndWait({ prompt: req.body.message });
});
res.json({ content: result?.data.content });
});
Comparación de patrones de aislamiento
| CLI independiente para cada usuario | Cli compartida + Aislamiento de sesión | Sesiones compartidas | |
|---|---|---|---|
| Isolation | |||
| ✅ Completo | |||
| ⚠️ Lógico | |||
| ❌ Compartido | |||
| Uso de recursos | Alto (CLI por usuario) | Bajo (una CLI) | Bajo (una CLI + sesión) |
| Complejidad | Medio | Bajo | Alto (bloqueado) |
| Flexibilidad de autenticación | |||
| ✅ Tokens por usuario | |||
| ⚠️ Token de servicio | |||
| ⚠️ Token de servicio | |||
| Mejor para | SaaS multicliente | Herramientas internas | Colaboración |
Escalado horizontal
Varios servidores de la CLI (Interfaz de Línea de Comandos) detrás de un equilibrador de carga

Requisito clave: El estado de sesión debe estar en el almacenamiento compartido para que cualquier servidor de la CLI pueda reanudar cualquier sesión.
// Route sessions to CLI servers
class CLILoadBalancer {
private servers: string[];
private currentIndex = 0;
constructor(servers: string[]) {
this.servers = servers;
}
// Round-robin selection
getNextServer(): string {
const server = this.servers[this.currentIndex];
this.currentIndex = (this.currentIndex + 1) % this.servers.length;
return server;
}
// Sticky sessions: same user always hits same server
getServerForUser(userId: string): string {
const hash = this.hashCode(userId);
return this.servers[hash % this.servers.length];
}
private hashCode(str: string): number {
let hash = 0;
for (let i = 0; i < str.length; i++) {
hash = (hash << 5) - hash + str.charCodeAt(i);
hash |= 0;
}
return Math.abs(hash);
}
}
const lb = new CLILoadBalancer([
"cli-1:4321",
"cli-2:4321",
"cli-3:4321",
]);
app.post("/chat", async (req, res) => {
const server = lb.getServerForUser(req.user.id);
const client = new CopilotClient({ cliUrl: server });
const session = await client.createSession({
sessionId: `user-${req.user.id}-chat`,
model: "gpt-4.1",
});
const response = await session.sendAndWait({ prompt: req.body.message });
res.json({ content: response?.data.content });
});
Sesiones persistentes y almacenamiento compartido

Las sesiones permanentes son más sencillas: anclar usuarios a servidores específicos de la CLI. No se necesita almacenamiento compartido, pero la distribución de carga es desigual.
El almacenamiento compartido permite que cualquier CLI controle cualquier sesión. Mejor distribución de carga, pero requiere almacenamiento en red para ~/.copilot/session-state/.
Escalado vertical
Ajuste de un único servidor de la CLI
Un único servidor de la CLI puede controlar muchas sesiones simultáneas. Consideraciones principales:

La administración del ciclo de vida de la sesión es clave para el escalado vertical:
// Limit concurrent active sessions
class SessionManager {
private activeSessions = new Map<string, Session>();
private maxConcurrent: number;
constructor(maxConcurrent = 50) {
this.maxConcurrent = maxConcurrent;
}
async getSession(sessionId: string): Promise<Session> {
// Return existing active session
if (this.activeSessions.has(sessionId)) {
return this.activeSessions.get(sessionId)!;
}
// Enforce concurrency limit
if (this.activeSessions.size >= this.maxConcurrent) {
await this.evictOldestSession();
}
// Create or resume
const session = await client.createSession({
sessionId,
model: "gpt-4.1",
});
this.activeSessions.set(sessionId, session);
return session;
}
private async evictOldestSession(): Promise<void> {
const [oldestId] = this.activeSessions.keys();
const session = this.activeSessions.get(oldestId)!;
// Session state is persisted automatically — safe to disconnect
await session.disconnect();
this.activeSessions.delete(oldestId);
}
}
Sesiones efímeras frente a persistentes

Sesiones efímeras
Para los puntos de conexión de API sin estado en los que cada solicitud es independiente:
app.post("/api/analyze", async (req, res) => {
const session = await client.createSession({
model: "gpt-4.1",
});
try {
const response = await session.sendAndWait({
prompt: req.body.prompt,
});
res.json({ result: response?.data.content });
} finally {
await session.disconnect(); // Clean up immediately
}
});
Sesiones persistentes
Para interfaces conversacionales o flujos de trabajo de larga duración:
// Create a resumable session
app.post("/api/chat/start", async (req, res) => {
const sessionId = `user-${req.user.id}-${Date.now()}`;
const session = await client.createSession({
sessionId,
model: "gpt-4.1",
infiniteSessions: {
enabled: true,
backgroundCompactionThreshold: 0.80,
},
});
res.json({ sessionId });
});
// Continue the conversation
app.post("/api/chat/message", async (req, res) => {
const session = await client.resumeSession(req.body.sessionId);
const response = await session.sendAndWait({ prompt: req.body.message });
res.json({ content: response?.data.content });
});
// Clean up when done
app.post("/api/chat/end", async (req, res) => {
await client.deleteSession(req.body.sessionId);
res.json({ success: true });
});
Despliegues de contenedores
Kubernetes con almacenamiento persistente
apiVersion: apps/v1
kind: Deployment
metadata:
name: copilot-cli
spec:
replicas: 3
selector:
matchLabels:
app: copilot-cli
template:
metadata:
labels:
app: copilot-cli
spec:
containers:
- name: copilot-cli
image: your-registry/copilot-cli:latest # See backend-services.md for how to build and push this image
args: ["--headless", "--host", "0.0.0.0", "--port", "4321"]
env:
- name: COPILOT_GITHUB_TOKEN
valueFrom:
secretKeyRef:
name: copilot-secrets
key: github-token
ports:
- containerPort: 4321
volumeMounts:
- name: session-state
mountPath: /root/.copilot/session-state
volumes:
- name: session-state
persistentVolumeClaim:
claimName: copilot-sessions-pvc
---
apiVersion: v1
kind: Service
metadata:
name: copilot-cli
spec:
selector:
app: copilot-cli
ports:
- port: 4321
targetPort: 4321

Instancias de Contenedores de Azure (Azure Container Instances)
containers:
- name: copilot-cli
image: your-registry/copilot-cli:latest # See backend-services.md for how to build and push this image
command: ["copilot", "--headless", "--host", "0.0.0.0", "--port", "4321"]
volumeMounts:
- name: session-storage
mountPath: /root/.copilot/session-state
volumes:
- name: session-storage
azureFile:
shareName: copilot-sessions
storageAccountName: myaccount
Lista de comprobación de envío

| Preocupación | Recomendación |
|---|---|
| Limpieza de sesión | Ejecute una limpieza periódica para eliminar las sesiones que hayan superado su TTL |
| Comprobaciones de estado | Hacer ping al servidor de la CLI periódicamente; reiniciar si no responde |
| Storage | Montar volúmenes persistentes para ~/.copilot/session-state/ |
| Secretos | Usa el gestor de secretos de tu plataforma (Vault, K8s Secrets, etc.) |
| Monitoring | Seguimiento del recuento de sesiones activas, latencia de respuesta, tasas de error |
| Locking | Uso de Redis o similar para el acceso a sesión compartida |
| Apagado | Purgar sesiones activas antes de detener los servidores de la CLI |
Limitaciones
| Limitación | Detalles |
|---|---|
| Sin bloqueo de sesión integrado | Implementación del bloqueo de nivel de aplicación para el acceso simultáneo |
| Sin equilibrio de carga integrado | Usar un balanceador de carga externo o una malla de servicios |
| El estado de sesión está basado en archivos | Requiere un sistema de archivos compartido para las configuraciones de varios servidores |
| Tiempo de espera de inactividad de 30 minutos | Las sesiones sin actividad se limpian automáticamente mediante la CLI |
| La CLI es un proceso único | Amplíe la capacidad añadiendo más instancias del servidor CLI, no subprocesos |
Pasos siguientes
- Reanudación y persistencia de sesión: Análisis en profundidad de las sesiones reanudables
- Configuración de servicios back-end: Configuración básica del lado servidor
- Configuración de OAuth de GitHub: autenticación multiusuario
- BYOK (bring your own key): Usa tu propio proveedor de modelos