Support running multiple dev instances on offset ports - #1495
Support running multiple dev instances on offset ports#1495Fabian-Fynn wants to merge 5 commits into
Conversation
|
Done for Demo here: vivid-planet/dextinity#5852. Will use this to try @manuelblum's needs-starter-pr-routine. |
a8cdd34 to
e296bfd
Compare
|
The script is up to date. |
Add assign-ports.sh and wire offset ports through the full dev chain so several checkouts can run `npm run dev` in parallel without host port collisions (Docker containers and Node services alike). - assign-ports.sh: reads every *_PORT from .env, finds a free +100..+900 offset, and writes base+offset into .env.local - package.json: wrap `dev-pm start` in `dotenv -c secrets` so the cascaded env (incl. .env.local) is exported into the environment that `docker compose up` inherits; Compose gives those real env vars precedence over the .env file, so containers bind offset host ports Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
e296bfd to
c934f92
Compare
| "scripts": { | ||
| "create-site-configs-env": "dotenv -e .env.secrets -e .env.local -e .env -- npx @comet/cli inject-site-configs -f site-configs/site-configs.ts -i .env.site-configs.tpl -o .env.site-configs --base64", | ||
| "dev": "npm run create-site-configs-env && dev-pm start", | ||
| "dev": "npm run create-site-configs-env && dotenv -c secrets -- dev-pm start", |
There was a problem hiding this comment.
This is necessary for Docker to pick up the overridden ports. However, this sets the variables for all scripts in dev-pm config. I'd prefer only setting it for Docker. Maybe we need a dev:docker script? Also, -c secrets isn't necessary, simply dotenv should be enough.
There was a problem hiding this comment.
Please don't call dotenv here. Instead, change the docker script in the dev-pm config to set -a; . .env; . .env.local; set +a; docker compose up (we did this in Demo and projects).
|
@nsams once suggested the following alternative: We could use a single # .env
PORT_OFFSET=0
API_PORT=4$PORT_OFFSET00
ADMIN_PORT=8$PORT_OFFSET00Your script would then only write the determined I like this idea. What do you think about it? |
|
@copilot resolve the merge conflicts in this pull request |
Good idea |
Co-authored-by: VPS-Fabi <296110786+VPS-Fabi@users.noreply.github.com>
Resolved by merging |
Replaces the bash script with a Node script run via native TS support (node assign-ports.mts, exposed as npm run assign-ports). Removes the lsof dependency by probing ports with bind attempts on 0.0.0.0, 127.0.0.1, and ::1 — Node sets SO_REUSEADDR, so a wildcard-only probe would miss localhost-bound listeners like Vite's dev server. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
All *_PORT values in .env now embed an offset digit via ${PORT_OFFSET}
(default 0), so assign-ports.mts only determines a free digit (0-9) and
writes PORT_OFFSET=<digit> to .env.local instead of rewriting every
port. The dotenv cascade expands .env.local's PORT_OFFSET inside the
.env port values.
Four ports had no zero digit to hold the offset and get new base
values: postgres 5432 -> 5032, jaeger UI 16686 -> 16086, jaeger OLTP
4318 -> 4018, valkey 6379 -> 6079.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
@nsams, @johnnyomair |
|
When it is a single variable in .env.local is the Script still needed? |
It's not needed necessarily. You can set the ports manually. In my opinion it's still useful for finding a free port offset automatically. |
| // Node sets SO_REUSEADDR, so a wildcard bind coexists with specific-address binds (and vice versa). | ||
| // Probe all three addresses to also catch localhost-only listeners like Vite's dev server. | ||
| async function portIsFree(port: number): Promise<boolean> { | ||
| for (const host of ["0.0.0.0", "127.0.0.1", "::1"]) { | ||
| const free = await new Promise<boolean>((resolve) => { | ||
| const server = createServer(); | ||
| server.once("error", (error: NodeJS.ErrnoException) => resolve(error.code !== "EADDRINUSE")); | ||
| server.once("listening", () => server.close(() => resolve(true))); | ||
| server.listen(port, host); | ||
| }); | ||
| if (!free) return false; | ||
| } | ||
| return true; | ||
| } |
There was a problem hiding this comment.
We could use the get-port package for this, but the custom implementation is fine as well.
| "scripts": { | ||
| "create-site-configs-env": "dotenv -e .env.secrets -e .env.local -e .env -- npx @comet/cli inject-site-configs -f site-configs/site-configs.ts -i .env.site-configs.tpl -o .env.site-configs --base64", | ||
| "dev": "npm run create-site-configs-env && dev-pm start", | ||
| "dev": "npm run create-site-configs-env && dotenv -c secrets -- dev-pm start", |
There was a problem hiding this comment.
Please don't call dotenv here. Instead, change the docker script in the dev-pm config to set -a; . .env; . .env.local; set +a; docker compose up (we did this in Demo and projects).
|
As an alternative to the script, we could instruct agents to find the offset themselves, for instance with https://github.com/sindresorhus/get-port-cli. However, I'm don't not sure how reliable this will work. |
I don't see a benefit in using an agent when a script can do it. |
Lets several checkouts run npm run dev in parallel without host port collisions — both Docker containers and Node services pick up offset ports.
Changes
Usage
./assign-ports.sh # picks a free offset → .env.local
npm run dev