Skip to content

スリープと復帰

サンドボックスがスリープするタイミング、復帰させるもの、中のプログラムがサンドボックスを稼働させ続ける方法やスリープ前に通知を受ける方法、再起動、マシンが失われてもプロセスを引き継ぐチェックポイント、長いスリープの後の削除。

更新

サンドボックスの status は、starting、running、sleeping、failed のいずれかです。awake_because は、実行中のサンドボックスが稼働している理由を示します。

スリープするタイミング

サンドボックスは、sleep_after_seconds(指定しなければ 30 秒。null ならスリープしない)の間、次の状態が続くとスリープします。

  • サンドボックスを待っている呼び出しがない(コマンドの結果を待っている呼び出しは数える。開いている出力ストリームやターミナルは数えない)
  • 処理をしていない:ゲストが数えた、サンドボックス自身のプログラムが使う CPU が、平均で 1 コアの 2% 未満
  • ネットワークリンクを通るパケットがない
  • 外部への TCP 接続を持っていない(専用の IPv6 アドレスでの接続は数えない。スリープ中は、マシンがその接続のキープアライブに代わりに応答する)
  • 静かになった時点で待機中だったタイマーがすべて発火した
  • 中のプログラムがホールドしていない(後述)、またはホールドが sleep_hold_max_ms 続いた

タイマーでサンドボックスが長く稼働し続けることはありません。サンドボックスはスリープし、プラットフォームが次のタイマーの期限の 0.4 秒前に、スリープしていた分だけ時計を進めて復帰させます。5 秒以内に期限が来るタイマーがある場合は、スリープしません。

クライアントの接続中は稼働。awake_ports(作成時か PATCH で、最大 16 ポート)を指定したサンドボックスは、それらのポートで、リンク経由でアップグレードされた接続が開いている間、稼働し続けます。9222 のブラウザの DevTools クライアントや、6080 の画面のビューアーのような WebSocket です。その間は稼働中として課金され、awake_connections が開いている接続の数を示します。このようなサンドボックスは、それらの接続、リクエスト、呼び出しだけでアイドルかどうかが決まります。自身の CPU、タイマー、外向きの接続では稼働し続けず、タイマーで復帰することもありません。最後の接続が終わってから sleep_after_seconds 後にスリープします。プラットフォームはそれらの接続で TCP キープアライブを有効にするため、接続を閉じずにいなくなったクライアントは約 1 分以内に検出され、connection_idle_seconds(1〜86,400 秒)で、どちらの方向にも何も流れない状態がその時間続いた接続を閉じます。1 回限りの実行では、どちらも指定できません。

POST /v1/sandboxes/{id}/sleep(glac sandboxes sleep web)で、すぐにスリープさせます。スリープ中のサンドボックスは、メモリ、プロセス、ディスク、ネットワーク上の位置を保持し、復帰すると、開いていた接続もそのまま続きます。

glac sandboxes update web --sleep-after-seconds 300     # five minutes idle
glac sandboxes update web --sleep-after-seconds never   # only when asked

復帰させるもの

必要とするものすべてです。コマンドの実行、ファイルの読み書き、ポートへのリンクに届くリクエスト、専用の IPv6 アドレスで開いているポートへの新しい接続(ネットワーク)、既存の接続に届く新しいデータ、ターミナルでのキー入力、スナップショット、フォーク、タイマーです。復帰させるための呼び出しはありません。サンドボックスを復帰させる必要があった API 呼び出しは、その時間をミリ秒単位で Server-Timing: wake;dur=… ヘッダーに返します。サンドボックスの読み取りや一覧表示では、何も復帰しません。

スリープ中のサンドボックスの sleep_tier は、スリープのしかたを示します。

sleep_tier 意味 課金対象
paused マシンのメモリ上に保持され、CPU は停止。最も速く復帰する メモリ(稼働中と同じ)。CPU はなし
saved メモリをマシンに保存 保持するもの(GB-月単位)
disk ディスクだけが残る。次の呼び出しでディスクから起動し、実行中だったものは失われる 保持するもの(GB-月単位)

内部から稼働させ続ける

応答した後もまだ処理が残っている(空にすべきキュー、終えるべき書き込み、送るべきログがある)サンドボックス内のプログラムは、自らサンドボックスを稼働させ続けられます。どのプロセスでも使える Unix ソケット /run/sbx/awake に接続し、+ を送るとホールドをかけ、- を送ると解除します。1 バイトごとに held <this connection's holds> <all holds> という行が返り、? は問い合わせだけを行います。接続のホールドは接続とともに終わります。プログラムが接続を閉じるか、どのような形であれ終了すると、ホールドはなくなるため、クラッシュでサンドボックスが稼働し続けることはありません。複数のプログラムのホールドや、1 つの接続での複数のホールドは足し合わされます。

import socket

def hold_awake():
    """Raises a hold; close the socket it returns to lower it."""
    s = socket.socket(socket.AF_UNIX)
    s.connect("/run/sbx/awake")
    s.sendall(b"+")
    s.recv(64)  # "held 1 1": the hold is in place
    return s
const net = require('node:net');
// Resolves once the hold is in place, with the function that lowers it.
const holdAwake = () => new Promise((resolve, reject) => {
  const s = net.connect('/run/sbx/awake', () => s.write('+'));
  s.once('data', () => resolve(() => s.end()));
  s.once('error', reject);
});
c, err := net.Dial("unix", "/run/sbx/awake")
if err == nil {
	c.Write([]byte("+"))
	bufio.NewReader(c).ReadString('\n') // "held 1 1"
	defer c.Close()                       // lowers it
}
  • ホールドされている間、サンドボックスは稼働中です。実行され、CPU とメモリは稼働中として計測されます。awake_because は its guest holds it awake (…) を示します。最後のホールドが解除されると、その時点からアイドルとなり、sleep_after_seconds 後にスリープします。
  • 上限の時間まで。sleep_hold_max_ms(0〜900,000 ミリ秒。指定しなければ 30,000 ミリ秒)は、ホールドがなければアイドルのサンドボックスを、ホールドで稼働させ続けられる時間です。それを過ぎると、ホールドにかかわらずスリープします。ホールドは復帰したときにも残っており、時間は次に静かになった時点から再び数えます。そのため、ホールドの解除を忘れたプログラムのコストは、毎回最大でその時間分です。0 ならホールドを無視します。
  • 通知を受ける。sleep_notice_ms(1〜60,000 ミリ秒。指定しなければなし)を設定すると、サンドボックスがアイドルでスリープするその時間前に、ソケットのすべての接続に sleep <ms> という行が送られます。保持しているものを書き出す、接続を閉じる、またはホールドをかけて稼働し続ける、といった対応ができます。応答の有無にかかわらず、その時間が過ぎるとスリープします。接続しているものがなければ、何も待ちません。上限によってホールドが終わった場合、行は sleep <ms> cap で、ホールドしてもそのスリープは止められません。要求したスリープ(POST …/sleep)は通知されません。
  • **必要になる前にかける。**サンドボックスが止まる直前(1 ミリ秒未満)にかけたホールドは、次の復帰から有効になります。自分で閉じていないのに接続が終わった場合(ソケットの背後のエージェントが再起動された場合)は、接続し直してください。

再起動と障害

POST /v1/sandboxes/{id}/restart(glac sandboxes restart web)は、ディスクから再起動します。実行中だったものは失われ、書き込まれたものは残ります。ID、名前、リンク、ドライブは変わりません。マシン自身が停止した場合(reboot、poweroff、カーネルパニック)も同じで、プラットフォームは 0.25 秒以内にそれを検知して稼働中として数えるのをやめ、それを必要とする次の呼び出しでディスクから起動します。そのコマンドを待っていた呼び出しには 409 command_lost が返ります。起動に失敗したサンドボックスは、failure と failure_code で理由を示します。再起動すれば解消します。

チェックポイント

マシンが失われたときに稼働中だったサンドボックスは、別のマシンでディスクから再起動し、実行中だったものは失われます(マシンが失われたとき)。チェックポイントがあれば、最新のチェックポイントから、そこでプロセスごと再開します。チェックポイントは、求めない限りオフです。

glac sandboxes create --name agent --checkpoint 10     # every 10 seconds while it is awake (on: 10)
glac sandboxes update agent --checkpoint off           # none from now on
  • API で:作成時か PATCH で checkpoint: {"every_seconds": 10}(1〜600 秒。指定しなければ 10 秒)を指定し、"checkpoint": null で解除します。SDK は作成と更新で checkpoint を受け付け、MCP サーバーには sandbox_checkpoint があります。
  • 取得されるものと、引き継ぎで失われるものは、キー別インスタンスと同じです。稼働中に、前回以降にメモリとディスクで変わった部分がオブジェクトストアに送られ、ドライブも一緒に固定されます。ドライブ以外のボリュームを持つサンドボックスでは取得されません。チェックポイントを参照してください。checkpoint が状況を示し(last_at、behind_seconds、stored_bytes、error)、プロセスごと戻った場合は sandbox.moved が with_processes: true を示します。
  • **場所。**チェックポイントを取れるのは、ディスクをオブジェクトストアにコピーし、メモリを階層で保持するマシンだけで、チェックポイント付きのサンドボックスはそうしたマシンに作られます。プラットフォームにそうしたマシンがなければ拒否され(409 checkpoints_unavailable)、すべて応答なしか満杯の間は 503 no_capacity(retryable)になります。
  • **料金。**最新のチェックポイントのうちストアが保持するものは、サンドボックスの実行中、スリープ中のサンドボックスの状態と同じく課金されます(state、1 GB-月あたり $0.02)。送信に料金はかかりません。

長くスリープすると削除される

サンドボックスには、削除されるまでにスリープしていられる時間を設定できます(delete_after_idle_ms)。プロジェクトでは、すべてのサンドボックスについて日数で設定できます(delete_after_idle_days を付けた PATCH /v1/project。1〜3650。glac project --delete-after-idle-days 30、SDK の update_project)。どちらも設定しなければ、スリープを理由に削除されることはなく、expires_at で指定した時刻に削除できます。利用上限額やプランによってスリープさせられたサンドボックスが、それを理由に削除されることはありません。

ナビゲーション

キーワードを入力して検索…

↑↓ 移動↵ 選択Esc 閉じる