Skip to content

非公式本サイトは非公式の日本語ドキュメントであり、Cloudflare 公式サイトではありません。最新情報はdevelopers.cloudflare.comをご確認ください。

出力をストリームする

最終更新 Markdown で表示Agent セットアップ

このガイドでは、コマンド、プロセス、コード実行からのリアルタイム出力の扱い方を説明します。

ストリーミングを使うとき

次の場合にストリーミングを使います。

  • リアルタイムのフィードバック - 進行状況をその場で表示する
  • 長時間の操作 - 時間がかかるビルド、テスト、インストール
  • 対話型アプリケーション - チャットボット、コード実行、ライブデモ
  • 大きな出力 - 出力を一度にではなく、段階的に処理する
  • ユーザー体験 - フィードバックなしでユーザーを待たせない

ストリーミングなし(exec())は次の場合に使います。

  • 短い操作 - 数秒で終わるコマンド
  • 小さな出力 - 出力がメモリに無理なく収まる場合
  • 後処理 - 処理の前に出力全体が必要な場合

コマンド実行をストリームする

execStream() を使ってリアルタイム出力を取得します。

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

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

const stream = await sandbox.execStream("npm run build");

for await (const event of parseSSEStream(stream)) {
	switch (event.type) {
		case "stdout":
			console.log(event.data);
			break;

		case "stderr":
			console.error(event.data);
			break;

		case "complete":
			console.log("Exit code:", event.exitCode);
			break;

		case "error":
			console.error("Failed:", event.error);
			break;
	}
}
import { getSandbox, parseSSEStream, type ExecEvent } from '@cloudflare/sandbox';

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

const stream = await sandbox.execStream('npm run build');

for await (const event of parseSSEStream<ExecEvent>(stream)) {
  switch (event.type) {
    case 'stdout':
      console.log(event.data);
      break;

    case 'stderr':
      console.error(event.data);
      break;

    case 'complete':
      console.log('Exit code:', event.exitCode);
      break;

    case 'error':
      console.error('Failed:', event.error);
      break;
  }
}

クライアントへストリームする

Server-Sent Events で、ストリーミング出力をユーザーへ返します。

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

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

export default {
	async fetch(request, env) {
		const sandbox = getSandbox(env.Sandbox, "builder");

		const stream = await sandbox.execStream("npm run build");

		return new Response(stream, {
			headers: {
				"Content-Type": "text/event-stream",
				"Cache-Control": "no-cache",
			},
		});
	},
};
import { getSandbox } from '@cloudflare/sandbox';

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

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    const sandbox = getSandbox(env.Sandbox, 'builder');

    const stream = await sandbox.execStream('npm run build');

    return new Response(stream, {
      headers: {
        'Content-Type': 'text/event-stream',
        'Cache-Control': 'no-cache'
      }
    });
  }
};

クライアント側での受信:

// Browser JavaScript
const eventSource = new EventSource("/build");

eventSource.addEventListener("stdout", (event) => {
	const data = JSON.parse(event.data);
	console.log(data.data);
});

eventSource.addEventListener("complete", (event) => {
	const data = JSON.parse(event.data);
	console.log("Exit code:", data.exitCode);
	eventSource.close();
});
// Browser JavaScript
const eventSource = new EventSource('/build');

eventSource.addEventListener('stdout', (event) => {
  const data = JSON.parse(event.data);
  console.log(data.data);
});

eventSource.addEventListener('complete', (event) => {
  const data = JSON.parse(event.data);
  console.log('Exit code:', data.exitCode);
  eventSource.close();
});

プロセスログをストリームする

バックグラウンドプロセスの出力を監視します。

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

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

const logStream = await sandbox.streamProcessLogs(process.id);

for await (const log of parseSSEStream(logStream)) {
	console.log(log.data);

	if (log.data.includes("Server listening")) {
		console.log("Server is ready");
		break;
	}
}
import { parseSSEStream, type LogEvent } from '@cloudflare/sandbox';

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

const logStream = await sandbox.streamProcessLogs(process.id);

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

  if (log.data.includes('Server listening')) {
    console.log('Server is ready');
    break;
  }
}

エラーを扱う

終了コードを確認し、ストリームエラーを処理します。

const stream = await sandbox.execStream("npm run build");

for await (const event of parseSSEStream(stream)) {
	switch (event.type) {
		case "stdout":
			console.log(event.data);
			break;

		case "error":
			throw new Error(`Build failed: ${event.error}`);

		case "complete":
			if (event.exitCode !== 0) {
				throw new Error(`Build failed with exit code ${event.exitCode}`);
			}
			break;
	}
}
const stream = await sandbox.execStream('npm run build');

for await (const event of parseSSEStream<ExecEvent>(stream)) {
  switch (event.type) {
    case 'stdout':
      console.log(event.data);
      break;

    case 'error':
      throw new Error(`Build failed: ${event.error}`);

    case 'complete':
      if (event.exitCode !== 0) {
        throw new Error(`Build failed with exit code ${event.exitCode}`);
      }
      break;
  }
}

ベストプラクティス

  • ストリームは必ず消費する - 未消費のままストリームを放置しない
  • すべてのイベントタイプを扱う - stdout、stderr、complete、error イベントを処理する
  • 終了コードを確認する - 0 以外の終了コードは失敗を示します
  • フィードバックを提供する - 長時間の操作ではユーザーに進行状況を見せる

関連リソース

役に立ちましたか?