INTEGRITY Документация

Запуск фоновых процессов

В этом руководстве показано, как запускать долго выполняющиеся фоновые процессы в песочнице, отслеживать их и управлять ими.

Когда использовать фоновые процессы

Используйте startProcess() вместо exec() когда:

Запустите фоновый процесс

import { getSandbox } from "@cloudflare/sandbox";

const sandbox = getSandbox(env.Sandbox, "my-sandbox");

// Start a web server
const server = await sandbox.startProcess("python -m http.server 8000");

console.log("Server started");
console.log("Process ID:", server.id);
console.log("PID:", server.pid);
console.log("Status:", server.status); // 'running'

// Process runs in background - your code continues
import { getSandbox } from '@cloudflare/sandbox';

const sandbox = getSandbox(env.Sandbox, 'my-sandbox');

// Start a web server
const server = await sandbox.startProcess('python -m http.server 8000');

console.log('Server started');
console.log('Process ID:', server.id);
console.log('PID:', server.pid);
console.log('Status:', server.status); // 'running'

// Process runs in background - your code continues

Настройте окружение процесса

Задайте рабочую директорию и переменные окружения:

const process = await sandbox.startProcess("node server.js", {
	cwd: "/workspace/api",
	env: {
		NODE_ENV: "production",
		PORT: "8080",
		API_KEY: env.API_KEY,
		DATABASE_URL: env.DATABASE_URL,
	},
});

console.log("API server started");
const process = await sandbox.startProcess('node server.js', {
  cwd: '/workspace/api',
  env: {
    NODE_ENV: 'production',
    PORT: '8080',
    API_KEY: env.API_KEY,
    DATABASE_URL: env.DATABASE_URL
  }
});

console.log('API server started');

Мониторинг статуса процесса

Просмотр и проверка выполняющихся процессов:

const processes = await sandbox.listProcesses();

console.log(`Running ${processes.length} processes:`);

for (const proc of processes) {
	console.log(`${proc.id}: ${proc.command} (${proc.status})`);
}

// Check if specific process is running
const isRunning = processes.some(
	(p) => p.id === processId && p.status === "running",
);
const processes = await sandbox.listProcesses();

console.log(`Running ${processes.length} processes:`);

for (const proc of processes) {
  console.log(`${proc.id}: ${proc.command} (${proc.status})`);
}

// Check if specific process is running
const isRunning = processes.some(p => p.id === processId && p.status === 'running');

Ожидание готовности процесса

Прежде чем продолжить, дождитесь готовности процесса:

const server = await sandbox.startProcess("node server.js");

// Wait for server to respond on port 3000
await server.waitForPort(3000);

console.log("Server is ready");
const server = await sandbox.startProcess('node server.js');

// Wait for server to respond on port 3000
await server.waitForPort(3000);

console.log('Server is ready');

Либо дождитесь определённых шаблонов в логах:

const server = await sandbox.startProcess("node server.js");

// Wait for log message
const result = await server.waitForLog("Server listening");
console.log("Server is ready:", result.line);
const server = await sandbox.startProcess('node server.js');

// Wait for log message
const result = await server.waitForLog('Server listening');
console.log('Server is ready:', result.line);

Мониторинг логов процесса

Транслируйте журналы в режиме реального времени:

import { parseSSEStream } from "@cloudflare/sandbox";

const server = await sandbox.startProcess("node server.js");

// Stream logs
const logStream = await sandbox.streamProcessLogs(server.id);

for await (const log of parseSSEStream(logStream)) {
	console.log(log.data);
}
import { parseSSEStream, type LogEvent } from '@cloudflare/sandbox';

const server = await sandbox.startProcess('node server.js');

// Stream logs
const logStream = await sandbox.streamProcessLogs(server.id);

for await (const log of parseSSEStream<LogEvent>(logStream)) {
  console.log(log.data);
}

Либо получите накопленные логи:

const logs = await sandbox.getProcessLogs(server.id);
console.log("Logs:", logs);
const logs = await sandbox.getProcessLogs(server.id);
console.log('Logs:', logs);

Остановите процессы

Остановите фоновые процессы и их дочерние процессы:

// Stop specific process (terminates entire process tree)
await sandbox.killProcess(server.id);

// Force kill if needed
await sandbox.killProcess(server.id, "SIGKILL");

// Stop all processes
await sandbox.killAllProcesses();
// Stop specific process (terminates entire process tree)
await sandbox.killProcess(server.id);

// Force kill if needed
await sandbox.killProcess(server.id, 'SIGKILL');

// Stop all processes
await sandbox.killAllProcesses();

killProcess() завершает указанный процесс и все порожденные им дочерние процессы. Это гарантирует, что процессы, работающие в фоновом режиме, не оставляют после завершения бесхозных дочерних процессов.

Например, если ваш процесс порождает несколько рабочих процессов или фоновых задач, killProcess() очистит всё дерево процессов:

// This script spawns multiple child processes
const batch = await sandbox.startProcess(
	'bash -c "process1 & process2 & process3 & wait"',
);

// killProcess() terminates the bash process AND all three child processes
await sandbox.killProcess(batch.id);
// This script spawns multiple child processes
const batch = await sandbox.startProcess(
  'bash -c "process1 & process2 & process3 & wait"'
);

// killProcess() terminates the bash process AND all three child processes
await sandbox.killProcess(batch.id);

Запуск нескольких процессов

Запускайте сервисы последовательно, дожидаясь готовности зависимостей:

// Start database first
const db = await sandbox.startProcess("redis-server");

// Wait for database to be ready
await db.waitForPort(6379, { mode: "tcp" });

// Now start API server (depends on database)
const api = await sandbox.startProcess("node api-server.js", {
	env: { DATABASE_URL: "redis://localhost:6379" },
});

// Wait for API to be ready
await api.waitForPort(8080, { path: "/health" });

console.log("All services running");
// Start database first
const db = await sandbox.startProcess('redis-server');

// Wait for database to be ready
await db.waitForPort(6379, { mode: 'tcp' });

// Now start API server (depends on database)
const api = await sandbox.startProcess('node api-server.js', {
  env: { DATABASE_URL: 'redis://localhost:6379' }
});

// Wait for API to be ready
await api.waitForPort(8080, { path: '/health' });

console.log('All services running');

Поддерживайте контейнеры активными для долго выполняющихся процессов

По умолчанию контейнеры автоматически завершают работу после 10 минут бездействия. Для длительных процессов, которые могут иметь периоды простоя (например, конвейеров CI/CD, пакетных заданий или задач мониторинга), используйте keepAlive параметр:

import { getSandbox, parseSSEStream } from "@cloudflare/sandbox";

export { Sandbox } from "@cloudflare/sandbox";

export default {
	async fetch(request, env) {
		// Enable keepAlive for long-running processes
		const sandbox = getSandbox(env.Sandbox, "build-job-123", {
			keepAlive: true,
		});

		try {
			// Start a long-running build process
			const build = await sandbox.startProcess("npm run build:production");

			// Monitor progress
			const logs = await sandbox.streamProcessLogs(build.id);

			// Process can run indefinitely without container shutdown
			for await (const log of parseSSEStream(logs)) {
				console.log(log.data);
				if (log.data.includes("Build complete")) {
					break;
				}
			}

			return new Response("Build completed");
		} finally {
			// Important: Must explicitly destroy when done
			await sandbox.destroy();
		}
	},
};
import { getSandbox, parseSSEStream, type LogEvent } from '@cloudflare/sandbox';

export { Sandbox } from '@cloudflare/sandbox';

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    // Enable keepAlive for long-running processes
    const sandbox = getSandbox(env.Sandbox, 'build-job-123', {
      keepAlive: true
    });

    try {
      // Start a long-running build process
      const build = await sandbox.startProcess('npm run build:production');

      // Monitor progress
      const logs = await sandbox.streamProcessLogs(build.id);

      // Process can run indefinitely without container shutdown
      for await (const log of parseSSEStream<LogEvent>(logs)) {
        console.log(log.data);
        if (log.data.includes('Build complete')) {
          break;
        }
      }

      return new Response('Build completed');
    } finally {
      // Important: Must explicitly destroy when done
      await sandbox.destroy();
    }
  }
};

Рекомендации

Устранение неполадок

Процесс завершается немедленно

Проверьте журналы, чтобы узнать причину:

const process = await sandbox.startProcess("node server.js");
await new Promise((resolve) => setTimeout(resolve, 1000));

const processes = await sandbox.listProcesses();
if (!processes.find((p) => p.id === process.id)) {
	const logs = await sandbox.getProcessLogs(process.id);
	console.error("Process exited:", logs);
}
const process = await sandbox.startProcess('node server.js');
await new Promise(resolve => setTimeout(resolve, 1000));

const processes = await sandbox.listProcesses();
if (!processes.find(p => p.id === process.id)) {
  const logs = await sandbox.getProcessLogs(process.id);
  console.error('Process exited:', logs);
}

Порт уже используется

Завершите существующие процессы перед запуском:

await sandbox.killAllProcesses();
const server = await sandbox.startProcess("node server.js");
await sandbox.killAllProcesses();
const server = await sandbox.startProcess('node server.js');