Meilleur pour : Développeurs de plateforme, générateurs SaaS, tout déploiement servant plus d’un petit nombre d’utilisateurs simultanés.
Concepts de base
Avant de choisir un modèle, comprenez trois dimensions de la mise à l’échelle :

Modèles d’isolation de session
Modèle 1 : interface CLI isolée par utilisateur
Chaque utilisateur obtient sa propre instance de serveur CLI. Isolation la plus forte : les sessions, la mémoire et les processus d’un utilisateur sont complètement séparés.

Quand utiliser :
- SaaS multilocataire où l’isolation des données est critique
- Utilisateurs disposant d’identifiants d’authentification différents
- Exigences de conformité (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);
}
}
}
Modèle 2 : interface CLI partagée avec isolation de session
Plusieurs utilisateurs partagent un serveur CLI, mais ont des sessions isolées via des ID de session uniques. Moins gourmand en ressources, mais isolation moindre.

Quand utiliser :
- Outils internes avec des utilisateurs approuvés
- Environnements contraints par des ressources
- Exigences d’isolation inférieures
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);
}
Modèle 3 : sessions partagées (collaboratives)
Plusieurs utilisateurs interagissent avec la même session, comme une salle de conversation partagée avec Copilot.

Quand utiliser :
- Outils de collaboration d’équipe
- Sessions de révision de code partagé
- Associer des assistants de programmation
⚠️Important: Le Kit de développement logiciel (SDK) ne fournit pas de verrouillage de session intégré. Vous devez sérialiser l’accès pour empêcher les écritures simultanées dans la même session.
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 });
});
Comparaison des modèles d’isolation
| Interface CLI isolée par utilisateur | Interface CLI partagée + isolation de session | Sessions partagées | |
|---|---|---|---|
| Isolation | |||
| ✅ Terminé | |||
| ⚠️ Logique | |||
| ❌ Partagé | |||
| Utilisation des ressources | High (CLI par utilisateur) | Faible (une interface CLI) | Faible (une seule session CLI) |
| Complexité | Moyenne | Faible | Élevé (verrouillage) |
| Flexibilité de l’authentification | |||
| ✅ Jetons par utilisateur | |||
| ⚠️ Jeton de service | |||
| ⚠️ Jeton de service | |||
| Idéal pour | SaaS multilocataire | Outils internes | Collaboration |
Scalabilité horizontale
Plusieurs serveurs CLI derrière un équilibreur de charge

Condition clé : L’état de session doit être sur le stockage partagé afin que n’importe quel serveur CLI puisse reprendre n’importe quelle session.
// 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 });
});
Sessions sticky et stockage partagé

Les sessions persistantes sont plus simples : affectez les utilisateurs à des serveurs CLI spécifiques. Aucun stockage partagé n’est nécessaire, mais la distribution de charge n’est pas inégale.
Le stockage partagé permet à n’importe quelle interface CLI de gérer n’importe quelle session. Meilleure distribution de charge, mais nécessite un stockage en réseau pour ~/.copilot/session-state/.
Scalabilité verticale
Réglage d’un serveur CLI unique
Un serveur CLI unique peut gérer de nombreuses sessions simultanées. Considérations clés :

La gestion du cycle de vie des sessions est essentielle à la mise à l’échelle verticale :
// 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);
}
}
Sessions éphémères et persistantes

Sessions éphémères
Pour les points de terminaison d’API sans état où chaque requête est indépendante :
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
}
});
Sessions persistantes
Pour les interfaces conversationnelles ou les workflows de longue durée :
// 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 });
});
Déploiements de conteneurs
Kubernetes avec stockage persistant
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

Azure Container Instances (Instances de Conteneur Azure)
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
Liste de contrôle de production

| Préoccupation | Recommandation |
|---|---|
| Nettoyage de session | Exécutez régulièrement un nettoyage pour supprimer les sessions plus anciennes que votre TTL |
| Vérifications d’intégrité | Envoyez régulièrement une requête ping au serveur CLI ; redémarrez-le s’il ne répond pas. |
| Stockage | Monter des volumes persistants pour ~/.copilot/session-state/ |
| Secrets | Utilisez le gestionnaire de secrets de votre plateforme (Coffre, K8s Secrets, etc.) |
| Monitoring | Suivre le nombre de sessions actives, la latence de réponse, les taux d’erreur |
| Locking | Utiliser Redis ou similaire pour l’accès à une session partagée |
| Arrêter | Laisser les sessions actives se terminer avant d’arrêter les serveurs CLI |
Limitations
| Limitation | Détails |
|---|---|
| Aucun verrouillage de session intégré | Implémenter le verrouillage au niveau de l’application pour l’accès simultané |
| Aucun équilibrage de charge intégré | Utiliser un LB externe ou un maillage de service |
| L’état de session est basé sur des fichiers | Nécessite un système de fichiers partagé pour les configurations multiserveurs |
| Délai d’inactivité de 30 minutes | Les sessions sans activité sont nettoyées automatiquement par l’interface CLI |
| L’interface CLI est un processus unique | Faites évoluer en ajoutant davantage d’instances du serveur CLI, pas de threads |
Étapes suivantes
- Reprise de session et persistance : Présentation approfondie des sessions pouvant être reprise
- Configuration des services principaux : Configuration côté serveur core
- configuration de GitHub OAuth : Authentification multi-utilisateur
- BYOK (bring your own key) : Utiliser votre propre fournisseur de modèles