mirror of
https://github.com/anomalyco/opencode.git
synced 2026-08-19 11:23:26 +00:00
feat(server): run modal sandboxes on the vm runtime (#41177)
This commit is contained in:
parent
5e6370363b
commit
9b7b402737
1 changed files with 36 additions and 11 deletions
|
|
@ -13,15 +13,30 @@ trap 'rm -f -- "$pidfile"' EXIT
|
|||
"$@"
|
||||
`
|
||||
|
||||
// Modal's VM runtime accepts process-group signals without delivering them
|
||||
// (kill(-pgid) returns 0 and nothing dies; direct-pid signals work), so the
|
||||
// group is enumerated from /proc and each member is signalled directly. The
|
||||
// second pass catches children forked between scan and signal.
|
||||
const KILL = `
|
||||
pidfile=$1
|
||||
sig=$2
|
||||
i=0
|
||||
while [ ! -s "$1" ] && [ "$i" -lt 250 ]; do sleep 0.02; i=$((i + 1)); done
|
||||
if [ -s "$1" ]; then
|
||||
pid=$(cat "$1")
|
||||
/bin/kill "-$2" "-$pid" 2>/dev/null || true
|
||||
else
|
||||
exit 47
|
||||
fi
|
||||
while [ ! -s "$pidfile" ] && [ "$i" -lt 250 ]; do sleep 0.02; i=$((i + 1)); done
|
||||
[ -s "$pidfile" ] || exit 47
|
||||
target=$(cat "$pidfile")
|
||||
pass=0
|
||||
while [ "$pass" -lt 2 ]; do
|
||||
for stat in /proc/[0-9]*/stat; do
|
||||
[ -e "$stat" ] || continue
|
||||
pid=\${stat#/proc/}
|
||||
pid=\${pid%/stat}
|
||||
set -- $(sed "s/.*) //" "$stat" 2>/dev/null)
|
||||
if [ "\${3:-}" = "$target" ]; then
|
||||
/bin/kill "-$sig" "$pid" 2>/dev/null || true
|
||||
fi
|
||||
done
|
||||
pass=$((pass + 1))
|
||||
done
|
||||
`
|
||||
|
||||
export interface ModalImageSpec {
|
||||
|
|
@ -54,7 +69,15 @@ export const createModalSandbox = async (options: ModalSandboxOptions) => {
|
|||
const app = await client.apps.fromName(options.app, { createIfMissing: true })
|
||||
const imageSpec = options.image ?? ubuntuImage
|
||||
const image = client.images.fromRegistry(imageSpec.registry).dockerfileCommands([...imageSpec.dockerfileCommands])
|
||||
const sandbox = await client.sandboxes.create(app, image, options.sandbox)
|
||||
// Always Modal's Full-VM runtime (beta, enabled per account): a real kernel
|
||||
// with real device nodes, so workspaces can run Docker and other
|
||||
// kernel-dependent workloads. Costs versus gVisor, measured Aug 2026:
|
||||
// per-exec floor ~285-535ms versus ~90-165ms, and filesystem snapshots only
|
||||
// (no memory snapshots — acceptable; fs-snapshot is the persistence design).
|
||||
const sandbox = await client.sandboxes.create(app, image, {
|
||||
...options.sandbox,
|
||||
experimentalOptions: { ...options.sandbox?.experimentalOptions, vm_runtime: true },
|
||||
})
|
||||
return {
|
||||
driver: makeModalDriver(sandbox),
|
||||
sandbox,
|
||||
|
|
@ -64,12 +87,14 @@ export const createModalSandbox = async (options: ModalSandboxOptions) => {
|
|||
|
||||
/**
|
||||
* Adapts Modal exec to the Environment driver. Files intentionally has no native
|
||||
* overrides: Modal exec and filesystem tools share the same roughly 175ms floor,
|
||||
* so the derived exec defaults are the simplest implementation with no measured loss.
|
||||
* overrides: exec latency dominates payload work (VM runtime floor measured
|
||||
* ~285-535ms per exec, Aug 2026), so the derived exec defaults are the simplest
|
||||
* implementation with no measured loss.
|
||||
*
|
||||
* Modal cannot signal a ContainerProcess. Each command therefore starts a new
|
||||
* process group and records its leader in a unique pid file; kill runs a second
|
||||
* sandbox command that signals that group. Pid files are removed best-effort.
|
||||
* sandbox command that enumerates that group from /proc and signals each member
|
||||
* directly (see KILL). Pid files are removed best-effort.
|
||||
*/
|
||||
export const makeModalDriver = (sandbox: Sandbox): Driver => {
|
||||
const spawn = Effect.fnUntraced(function* (command: Command) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue