# Escalabilidade e multitenância

Projete sua implantação do SDK Copilot para atender a vários usuários, manipular sessões simultâneas e dimensionar horizontalmente em toda a infraestrutura. Este guia aborda padrões de isolamento de sessão, topologias de dimensionamento e práticas recomendadas de produção.

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

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

Para opções e padrões no nível do SDK, consulte [Multilocação e implantações de servidores](/pt/copilot/how-tos/copilot-sdk/setup/multi-tenancy).

**Melhor para:** Desenvolvedores de plataforma, construtores de SaaS, qualquer implantação que atende a mais de um punhado de usuários simultâneos.

## Conceitos principais

Antes de escolher um padrão, entenda três dimensões de dimensionamento:

![Diagrama: Fluxograma mostrando o processo descrito.](/assets/images/help/copilot/copilot-sdk/setup-scaling-diagram-0.png)

## Padrões de isolamento de sessões

### Padrão 1: CLI isolada por usuário

Cada usuário obtém sua própria instância de servidor da CLI. Isolamento mais forte: as sessões, a memória e os processos de um usuário são completamente separados.

![Diagrama: Fluxograma mostrando o processo descrito.](/assets/images/help/copilot/copilot-sdk/setup-scaling-diagram-1.png)

**Quando usar:**

* SaaS multilocatário em que o isolamento de dados é crítico
* Usuários com credenciais de autenticação diferentes
* Requisitos de conformidade (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);
        }
    }
}
```

### Padrão 2: CLI compartilhada com isolamento de sessão

Vários usuários compartilham um servidor da CLI, mas têm sessões isoladas por meio de IDs de sessão exclusivas. Mais leve em recursos, mas isolamento mais fraco.

![Diagrama: Fluxograma mostrando o processo descrito.](/assets/images/help/copilot/copilot-sdk/setup-scaling-diagram-2.png)

**Quando usar:**

* Ferramentas internas com usuários confiáveis
* Ambientes restritos a recursos
* Requisitos de isolamento mais baixos

```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);
}
```

### Padrão 3: sessões compartilhadas (colaborativas)

Vários usuários interagem com a mesma sessão, como uma sala de chat compartilhada com o Copilot.

![Diagrama: Fluxograma mostrando o processo descrito.](/assets/images/help/copilot/copilot-sdk/setup-scaling-diagram-3.png)

**Quando usar:**

* Ferramentas de colaboração em equipe
* Sessões de revisão de código compartilhado
* Assistentes de programação em par

> ⚠️**Importante:** O SDK não fornece bloqueio de sessão interno. Você **deve** serializar o acesso para evitar gravações simultâneas na mesma sessão.

```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 });
});
```

## Comparação de padrões de isolamento

|                                   | CLI isolada por usuário | CLI compartilhada + Isolamento de sessão | Sessões compartilhadas   |
| --------------------------------- | ----------------------- | ---------------------------------------- | ------------------------ |
| **Isolation**                     |                         |                                          |                          |
| ✅ Concluído                       |                         |                                          |                          |
| ⚠️ Lógico                         |                         |                                          |                          |
| ❌ Compartilhado                   |                         |                                          |                          |
| **Uso de recursos**               | Alta (CLI por usuário)  | Baixo (uma CLI)                          | Baixo (uma CLI + sessão) |
| **Complexidade**                  | Medium                  | Baixo                                    | Alto (bloqueio)          |
| **Flexibilidade de autenticação** |                         |                                          |                          |
| ✅ Tokens por usuário              |                         |                                          |                          |
| ⚠️ Token de serviço               |                         |                                          |                          |
| ⚠️ Token de serviço               |                         |                                          |                          |
| **Mais adequado para**            | SaaS multilocatário     | Ferramentas internas                     | Colaboração              |

## Escalabilidade horizontal

### Vários servidores CLI por trás de um balanceador de carga

![Diagrama: Fluxograma mostrando o processo descrito.](/assets/images/help/copilot/copilot-sdk/setup-scaling-diagram-4.png)

**Requisito de chave:** O estado da sessão deve estar no **armazenamento compartilhado** para que qualquer servidor da CLI possa retomar qualquer sessão.

```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-4.1",
    });

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

### Sessões persistentes versus armazenamento compartilhado

![Diagrama: Fluxograma mostrando o processo descrito.](/assets/images/help/copilot/copilot-sdk/setup-scaling-diagram-5.png)

**Sessões persistentes** são mais simples: mantêm os usuários vinculados a servidores específicos de CLI. Não é necessário armazenamento compartilhado, mas a distribuição de carga é desigual.

**O armazenamento compartilhado** permite que qualquer CLI manipule qualquer sessão. Melhor distribuição de carga, mas requer armazenamento em rede para `~/.copilot/session-state/`.

## Escalonamento vertical

### Ajustando um único servidor da CLI

Um único servidor da CLI pode lidar com muitas sessões simultâneas. Principais considerações:

![Diagrama: Fluxograma mostrando o processo descrito.](/assets/images/help/copilot/copilot-sdk/setup-scaling-diagram-6.png)

**O gerenciamento do ciclo de vida** da sessão é fundamental para o dimensionamento 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-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);
    }
}
```

## Sessões efêmeras versus persistentes

![Diagrama: Fluxograma mostrando o processo descrito.](/assets/images/help/copilot/copilot-sdk/setup-scaling-diagram-7.png)

### Sessões efêmeras

Para endpoints de API sem estado, em que cada solicitação é independente:

```typescript
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
    }
});
```

### Sessões persistentes

Para interfaces de conversa ou fluxos de trabalho de execução longa:

```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-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 });
});
```

## Implantações de contêiner

### Kubernetes com armazenamento 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: Fluxograma mostrando o processo descrito.](/assets/images/help/copilot/copilot-sdk/setup-scaling-diagram-8.png)

### Instâncias de Contêiner do Azure

```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 verificação de produção

![Diagrama: Fluxograma mostrando o processo descrito.](/assets/images/help/copilot/copilot-sdk/setup-scaling-diagram-9.png)

| Preocupação                     | Recomendação                                                                   |
| ------------------------------- | ------------------------------------------------------------------------------ |
| **Limpeza de sessão**           | Execute uma limpeza periódica para excluir sessões com mais tempo do que o TTL |
| **Verificações de integridade** | Executar ping no servidor da CLI periodicamente; reiniciar se não responder    |
| Armazenamento                   | Montar volumes persistentes para `~/.copilot/session-state/`                   |
| **Segredos**                    | Use o gerenciador de segredos da sua plataforma (Vault, K8s Secrets, etc.)     |
| **Monitorização**               | Acompanhar contagem de sessão ativa, latência de resposta, taxas de erro       |
| **Locking**                     | Usar Redis ou semelhante para acesso de sessão compartilhado                   |
| **Desligamento**                | Encerrar sessões ativas antes de parar os servidores de CLI                    |

## Limitações

| Limitation                                  | Detalhes                                                                         |
| ------------------------------------------- | -------------------------------------------------------------------------------- |
| **Nenhum bloqueio de sessão interno**       | Implementar o bloqueio no nível do aplicativo para acesso simultâneo             |
| **Nenhum balanceamento de carga interno**   | Usar LB externo ou malha de serviço                                              |
| **O estado da sessão é baseado em arquivo** | Requer sistema de arquivos compartilhado para configurações de vários servidores |
| **Tempo limite ocioso de 30 minutos**       | As sessões sem atividade são limpas automaticamente pela CLI                     |
| **A CLI é de processo único**               | Escale adicionando mais instâncias do servidor CLI, não threads                  |

## Próximas Etapas 

* **[Retomada e persistência da sessão](/pt/copilot/how-tos/copilot-sdk/features/session-persistence)**: Análise aprofundada de sessões retomáveis
* **[Configuração de serviços de back-end](/pt/copilot/how-tos/copilot-sdk/setup/backend-services)**: Configuração principal do lado do servidor
* **[Configuração do OAuth do GitHub](/pt/copilot/how-tos/copilot-sdk/setup/github-oauth)**: Autenticação multiusuário
* **[BYOK (Bring Your Own Key - traga sua própria chave)](/pt/copilot/how-tos/copilot-sdk/auth/byok)**: Usar seu próprio provedor de modelos