Runtime и sandbox
Модель изоляции и жизненный цикл выполнения скриптов
Принцип
Пользовательские скрипты не получают отдельный Docker-контейнер. Все runs выполняются как изолированные subprocess внутри сервиса runtime.
Runtime Engine
├── Redis BLPOP runtime:jobs
├── SandboxPool (semaphore max_concurrent)
│ └── Sandbox на каждый run
│ ├── venv (на workspace)
│ ├── subprocess python entrypoint
│ ├── RLIMIT_CPU / RLIMIT_AS
│ └── wall-clock timeout
└── POST /internal/runs/* → backend
Жизненный цикл run
- Очередь — backend создаёт
Run(статусqueued), кладёт job в Redis - Старт — runtime забирает job, вызывает
/internal/runs/start - Выполнение — sandbox запускает
entrypointс секретами в env (SECRET_*) - Логи — stdout/stderr → WebSocket + PostgreSQL
- Завершение — exit code, duration →
/internal/runs/complete - Остановка — UI публикует
stopвrun:{id}:control, SIGTERM процессу
Изоляция
| Слой | Механизм |
|---|---|
| Процесс | subprocess.Popen |
| ФС | /workspaces/{script_id}/{run_id}/ |
| Зависимости | pip install -r requirements.txt в локальный venv |
| CPU/память | resource.setrlimit |
| Время | asyncio.wait_for wall timeout |
| Секреты | Шифрование at rest, инъекция при run |
Масштабирование
docker compose -f docker-compose.prod.yml — несколько реплик runtime, общая Redis-очередь.
Горячая перезагрузка кода
Сохранение скрипта в UI → Redis script:updated → runtime инвалидирует кэш venv → следующий run с новым кодом без перезапуска контейнеров.