Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 17 additions & 2 deletions deploy/targets/local-docker.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,24 @@

import fs from 'node:fs/promises'
import path from 'node:path'
import net from 'node:net'
import { spawn } from 'node:child_process'
import crypto from 'node:crypto'

// Ask the OS for a free ephemeral port on the loopback interface. Far safer
// than a random pick under concurrent deploys, where two cells could otherwise
// choose the same port and the second `docker run -p` would fail.
function findFreePort() {
return new Promise((resolve, reject) => {
const srv = net.createServer()
srv.on('error', reject)
srv.listen(0, '127.0.0.1', () => {
const { port } = srv.address()
srv.close(() => resolve(port))
})
})
}

function run(cmd, args, opts = {}) {
return new Promise((resolve, reject) => {
const p = spawn(cmd, args, { stdio: opts.quiet ? 'pipe' : 'inherit', ...opts })
Expand Down Expand Up @@ -84,8 +99,8 @@ export async function deployLocalDocker({ manifest, manifestPath, repoRoot }) {
// Tear down any old container with the same name (idempotency for re-deploys)
await run('docker', ['rm', '-f', containerName], { quiet: true }).catch(() => {})

// Pick a free local port
const port = 8000 + Math.floor(Math.random() * 1000)
// Pick a free local port (OS-assigned, avoids collisions across concurrent deploys)
const port = await findFreePort()

// Run detached
console.log(` [docker run] ${containerName} on :${port}`)
Expand Down
4 changes: 3 additions & 1 deletion polyrange.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -273,8 +273,10 @@ async function cmdDestroy() {
async function cmdOne() {
const cls = flags.class
const tier = flags.tier ?? '0'
const target = flags.target ?? 'fly' // fly | local-docker
if (!cls) throw new Error('--class=X is required')
const args = ['generator/deploy.mjs', `--class=${cls}`, `--tier=${tier}`, '--target=fly']
const args = ['generator/deploy.mjs', `--class=${cls}`, `--tier=${tier}`, `--target=${target}`]
if (flags.region) args.push(`--region=${flags.region}`)
if (flags.ephemeral) args.push('--ephemeral')
const child = spawn('node', args, { stdio: 'inherit', cwd: REPO_ROOT, env: process.env })
await new Promise((resolve) => child.on('close', resolve))
Expand Down