여러 샌드박스에 걸쳐 작업 실행하기
여러 샌드박스에 걸쳐 작업 실행하기 (Run work across many sandboxes)
여러 기존 샌드박스에 명령을 실행하면서 동시성을 제한하는 방법을 알아볼게요.
출처: 문서
본문
여러 기존 샌드박스에 걸쳐 명령을 실행하면서 동시성(concurrency)을 제한해요. 진단 정보를 모으거나, 같은 작업을 독립적인 워크스페이스 그룹에 적용할 수 있어요.
인증된 클라이언트와 인자 배열을 사용해요. 이 작업을 위해 여러분의 애플리케이션이 소유한 샌드박스에서만 명령을 실행해요.
실행 중인 샌드박스 선택하기 (Select running sandboxes)
샌드박스 컬렉션을 순회하며 실행 중인 핸들을 모아요. 예시는 클라이언트에 보이는 모든 실행 중인 샌드박스를 선택해요. 부수 효과가 있는 명령을 실행하기 전에 여러분의 애플리케이션 작업으로 선택 범위를 좁히세요.
목록 조회와 실행은 별개의 요청이에요. 그 사이에 샌드박스 상태가 바뀔 수 있으므로, 실행 단계에서도 실패 처리는 여전히 필요해요.
TypeScript
const running: Sandbox[] = [];
for await (const sandbox of client.all()) {
if (sandbox.status === 'running') running.push(sandbox);
}
return running;
전체 TypeScript 예시: fanout/spread.ts
import type { Sandbox, Sandboxes } from '@docker/sandboxes';
export async function runningSandboxes(client: Sandboxes) {
const running: Sandbox[] = [];
for await (const sandbox of client.all()) {
if (sandbox.status === 'running') running.push(sandbox);
}
return running;
}
개별 결과 모으기 (Collect individual results)
동시성 상한(concurrency bound)을 정하고 각 선택된 샌드박스에서 명령을 실행해요. 예시는 각 결과나 실패를 샌드박스 이름과 함께 유지하므로, 요청 하나가 실패해도 다른 결과를 버리지 않아요.
요청 실패와 프로세스 종료 코드를 모두 확인해요. 반환된 프로세스 결과에 0이 아닌 종료 코드가 포함될 수 있어요.
동시성을 여러분의 계정 한도와 애플리케이션 메모리 예산 아래로 유지하세요. 출력이 크면 모두 모으는 대신 결과를 스트리밍해요. 예시는 기존 샌드박스를 삭제하지 않아요.
TypeScript
const outcomes: Outcome[] = [];
const size = Number.isFinite(bound) ? Math.max(1, Math.trunc(bound)) : 1;
for (let start = 0; start < sandboxes.length; start += size) {
const group = sandboxes.slice(start, start + size);
const settled = await Promise.allSettled(
group.map((sandbox) =>
sandbox.processes.run({ args }, { timeoutMs: 300_000 }),
),
);
settled.forEach((result, index) => {
outcomes.push(
result.status === 'fulfilled'
? { sandboxName: group[index].name, response: result.value }
: { sandboxName: group[index].name, failure: result.reason },
);
});
}
return outcomes;
전체 TypeScript 예시: fanout/gather.ts
import type { RunResult, Sandbox } from '@docker/sandboxes';
export type Outcome = {
sandboxName: string;
response?: RunResult;
failure?: unknown;
};
export async function runOnEach(
sandboxes: Sandbox[],
args: string[],
bound: number,
) {
const outcomes: Outcome[] = [];
const size = Number.isFinite(bound) ? Math.max(1, Math.trunc(bound)) : 1;
for (let start = 0; start < sandboxes.length; start += size) {
const group = sandboxes.slice(start, start + size);
const settled = await Promise.allSettled(
group.map((sandbox) =>
sandbox.processes.run({ args }, { timeoutMs: 300_000 }),
),
);
settled.forEach((result, index) => {
outcomes.push(
result.status === 'fulfilled'
? { sandboxName: group[index].name, response: result.value }
: { sandboxName: group[index].name, failure: result.reason },
);
});
}
return outcomes;
}
더 알아보기 (Learn more)
전체 레시피 목록은 Browse all recipes 에서 확인할 수 있어요.