Лучше всего для: Разработчики платформы, SaaS-конструкторы, любое развертывание, обслуживающее более нескольких одновременных пользователей.
Основные понятия
Перед выбором паттерна изучите три измерения масштабирования:

Шаблоны изоляции сессий
Шаблон 1: изолированный CLI на пользователя
Каждый пользователь получает свой собственный экземпляр CLI-сервера. Самая сильная изоляция — сессии, память и процессы пользователя полностью разделены.

Когда использовать:
- Мультиарендный SaaS, где изоляция данных критически важна
- Пользователи с разными авторскими данными
- Требования к соблюдению (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);
}
}
}
Шаблон 2: общий CLI с изоляцией сессий
Несколько пользователей используют один CLI-сервер, но имеют изолированные сессии через уникальные идентификаторы сессий. Ресурсы меньше, но изоляция слабее.

Когда использовать:
- Внутренние инструменты с надёжными пользователями
- Среды с ограниченными ресурсами
- Низкие требования к изоляции
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);
}
Шаблон 3: совместные сессии (совместные)
Несколько пользователей взаимодействуют с одной и той же сессией — как в общем чате с Copilot.

Когда использовать:
- Инструменты для командной работы
- Сессии совместного обзора кода
- Парные ассистенты программирования
⚠️Важно: SDK не обеспечивает встроенную блокировку сессий. Необходимо сериализировать доступ, чтобы предотвратить одновременные записи в одну и ту же сессию.
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 });
});
Сравнение моделей изоляции
| Изолированный CLI на пользователя | Общая CLI + изоляция сессий | Общие сеансы | |
|---|---|---|---|
| Isolation | |||
| ✅ Завершено | |||
| ⚠️ Логичность | |||
| ❌ Общие | |||
| Использование ресурсов | Высокий (CLI на пользователя) | Низкий (один CLI) | Низкий уровень (один CLI + сеанс) |
| Сложность | Средняя | Низкий | Высокий (блокировка) |
| Гибкость аутентификации | |||
| ✅ Токены на пользователя | |||
| ⚠️ Сервисный токен | |||
| ⚠️ Сервисный токен | |||
| лучше всего подходит для | Многопользовательский SaaS | Внутренние инструменты | Collaboration |
Горизонтальное масштабирование
Несколько CLI-серверов за балансировщиком нагрузки

Ключевое требование: Состояние сессии должно находиться на общем хранилище , чтобы любой CLI-сервер мог возобновить любую сессию.
// 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 });
});
Закреплённые сессии против общего хранилища

Закреплённые сессии проще — пользователи связаны с определёнными CLI-серверами. Общее хранилище не требуется, но распределение нагрузки неравномерное.
Общее хранилище позволяет любому CLI обрабатывать любую сессию. Лучшее распределение нагрузки, но требует сетевого хранения для ~/.copilot/session-state/.
Вертикальное масштабирование
Настройка одного CLI-сервера
Один CLI-сервер может обрабатывать множество одновременных сессий. Ключевые вопросы

Управление жизненным циклом сессии является ключом к вертикальному масштабированию:
// 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);
}
}
Эфемерные и постоянные сессии

Эфемерные сессии
Для конечных точек API без состояния, где каждый запрос независим:
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
}
});
Постоянные сеансы
Для разговорных интерфейсов или долгосрочных рабочих процессов:
// 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 });
});
Развертывания контейнеров
Kubernetes с постоянным хранением памяти
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 (инстансы контейнеров в 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
Контрольный список рабочей среды

| Беспокойство | Recommendation |
|---|---|
| Уборка сессии | Запускайте периодическую очистку, чтобы удалять сессии старше вашего TTL |
| Медицинские проверки | Периодически пингуйте CLI-сервер; Перезагрузка, если не отвечает |
| Хранение | Монтировать постоянные тома для ~/.copilot/session-state/ |
| Секреты | Используйте менеджер секретов вашей платформы (Vault, K8s Secrets и т.д.) |
| Monitoring | Отслеживайте количество активных сессий, задержку ответа, уровень ошибок |
| Locking | Используйте Redis или подобные для доступа к совместной сессии |
| Завершение работы | Опустошите активные сессии перед закрытием CLI-серверов |
Ограничения
| Limitation | Details |
|---|---|
| Нет встроенной блокировки сессии | Реализовать блокировку на уровне приложения для одновременного доступа |
| Нет встроенной балансировки нагрузки | Используйте внешний LB или сервисный меш |
| Состояние сессии основано на файлах | Требуется общая файловая система для настройки нескольких серверов |
| 30-минутный тайм-аут на холостом ходу | Занятия без активности автоматически очищаются CLI |
| CLI — это однопроцессный процесс | Масштабируйтесь, добавляя больше экземпляров CLI-серверов, а не потоков |
Дальнейшие действия
- Возобновление сессии и сохранение: Глубокий анализ сессий, которые можно возобновить
- Настройка серверных сервисов: Основная серверная настройка
- Настройка GitHub OAuth: Многопользовательская аутентификация
- BYOK (bring your own key): Используйте своего собственного поставщика моделей