# Escalabilidad y multitenencia

Diseñe la implementación del SDK de Copilot para atender a varios usuarios, controlar sesiones simultáneas y escalar horizontalmente en toda la infraestructura. En esta guía se tratan los patrones de aislamiento de sesión, las topologías de escalado y los procedimientos recomendados de producción.

<!-- markdownlint-disable GHD046 GHD005 -->

<!-- Suppressed: GHD046 (outdated release terminology), GHD005 (hardcoded data variable) -->

Para conocer los patrones y las opciones de nivel de SDK, consulte [Multiinquilino e implementaciones de servidor](/es/copilot/how-tos/copilot-sdk/setup/multi-tenancy).

**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:

![Diagrama: Diagrama de flujo que muestra el proceso descrito.](/assets/images/help/copilot/copilot-sdk/setup-scaling-diagram-0.png)

## 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.

![Diagrama: Diagrama de flujo que muestra el proceso descrito.](/assets/images/help/copilot/copilot-sdk/setup-scaling-diagram-1.png)

**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)

```typescript
// 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.

![Diagrama: Diagrama de flujo que muestra el proceso descrito.](/assets/images/help/copilot/copilot-sdk/setup-scaling-diagram-2.png)

**Cuándo usar:**

* Herramientas internas con usuarios de confianza
* Entornos con restricción de recursos
* Requisitos de aislamiento más bajos

```typescript
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.

![Diagrama: Diagrama de flujo que muestra el proceso descrito.](/assets/images/help/copilot/copilot-sdk/setup-scaling-diagram-3.png)

**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.

```typescript
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** |                                     |                                        |                         |
| ✅ Tókenes 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

![Diagrama: Diagrama de flujo que muestra el proceso descrito.](/assets/images/help/copilot/copilot-sdk/setup-scaling-diagram-4.png)

**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.

```typescript
// 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-5.4",
    });

    const response = await session.sendAndWait({ prompt: req.body.message });
    res.json({ content: response?.data.content });
});
```

### Sesiones persistentes y almacenamiento compartido

![Diagrama: Diagrama de flujo que muestra el proceso descrito.](/assets/images/help/copilot/copilot-sdk/setup-scaling-diagram-5.png)

**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:

![Diagrama: Diagrama de flujo que muestra el proceso descrito.](/assets/images/help/copilot/copilot-sdk/setup-scaling-diagram-6.png)

**La administración del ciclo de vida de la sesión** es clave para el escalado vertical:

```typescript
// 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-5.4",
        });

        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

![Diagrama: Diagrama de flujo que muestra el proceso descrito.](/assets/images/help/copilot/copilot-sdk/setup-scaling-diagram-7.png)

### Sesiones efímeras

Para los puntos de conexión de API sin estado en los que cada solicitud es independiente:

```typescript
app.post("/api/analyze", async (req, res) => {
    const session = await client.createSession({
        model: "gpt-5.4",
    });

    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:

```typescript
// 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-5.4",
        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

```yaml
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
```

![Diagrama: Diagrama de flujo que muestra el proceso descrito.](/assets/images/help/copilot/copilot-sdk/setup-scaling-diagram-8.png)

### Instancias de Contenedores de Azure (Azure Container Instances)

```yaml
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

![Diagrama: Diagrama de flujo que muestra el proceso descrito.](/assets/images/help/copilot/copilot-sdk/setup-scaling-diagram-9.png)

| 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 LB 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](/es/copilot/how-tos/copilot-sdk/features/session-persistence)**: Análisis en profundidad de las sesiones reanudables
* **[Configuración de servicios back-end](/es/copilot/how-tos/copilot-sdk/setup/backend-services)**: Configuración básica del lado servidor
* **[Configuración de OAuth de GitHub](/es/copilot/how-tos/copilot-sdk/setup/github-oauth)**: autenticación multiusuario
* **[BYOK (traiga su propia clave)](/es/copilot/how-tos/copilot-sdk/auth/byok)**: Usa tu propio proveedor de modelos