site serve and view: pick a free port when the registry gives none, and report a held port as taken #249
Labels
No labels
blocked
bug
decision
duplicate
enhancement
help wanted
invalid
landed?
question
ready-to-merge
stale
wontfix
bug
duplicate
enhancement
help wanted
invalid
question
wontfix
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
allod/tools#249
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Let
allod site servestart a preview for a site that has no port in the registry, on a free port it picks, and letallod site viewfind that port by itself, so serving and viewing a site for the first time needs no registry edit and no invented port number. The same change makes a start report success only when the port is held by the preview itself, which a picked port depends on.Primary goals:
preview_portand no--port,servepicks a free port on 127.0.0.1, starts the preview there and prints the address.servefor a running preview prints the same address, and--stopneeds no port.viewasks the serving machine — with no port of its own,viewforwards the port the remote start reports.preview_portis served there, unchanged, and--portstill overrides both.Current state: no port
serverefuses a site with no port (cmd/allod/site_serve.go:108, at3f917eb):The way past it is
--port <n>with a number the reader makes up, without knowing which ports are free or in use by another site's preview.viewrefuses the same way (cmd/allod/site_view.go:35) and discards what the remote start prints (site_view.go:48), so it cannot learn a port from the machine that serves.The refusal is reached in two situations that look the same to the reader: the site is new and has no registry entry yet, and the machine reads a registry that does not list the site. The second is tracked in allod/archetypes#119.
A fixed port per site exists so that the two machines agree on it without asking each other.
viewalready runs a command on the serving machine before it forwards, so it can ask.Current state: a port held by something else
Observed on a dev VM, with another process listening on the site's port before the start, for three apps (zola, live-server, Vite with
--strictPort):The journal of the unit for the same start, live-server's case:
Each app failed as its contract requires and did not move to another port.
servehad already returned:sitePreviewWait(site_serve.go:201) takes a connection to the port as good news while the unit is up, and the unit is still up whilenix runis evaluating, before the app has tried to bind. The comment above that function names the case. The printed address is the other process's.systemctl showa moment after the failure readsResult=successandExecMainStatus=0, so the failure is in the journal and not in the unit's properties.Default
Before starting a unit that is not running,
serveconnects to the port once. An answer means the port is taken: exit 1, naming the port, and nothing is started. This check is what a registry port and--portget too.For a site with no port,
serveasks the kernel for a free one by binding 127.0.0.1 port 0, releases it, and hands that number to the unit as it hands a registry port today. The port is recorded with the unit, so a laterservefor the same site reads it back while the unit is up and picks a new one only when it is not. The message says the port was picked, and that apreview_portin the registry makes it permanent.Between releasing the port and the app binding it another process can take it. The app then fails and
servereports a stopped unit with its log lines. One retry with a new port is enough; more hides a real fault.view, with no port from its registry or--port, reads the address the remote start prints and forwards that port. With a port of its own it passes it along as today.Alternative for the held port: accept a connection only when the listening socket belongs to a process of the unit. It closes the window between the check and the bind as well, and needs the socket's owner read from the kernel. Left as a follow-up unless the check before the start proves not enough.
Alternative for the missing port: a fixed default port for every site without one. Rejected because two such sites collide on the second start.
Validation
--port: exit 0, an address on 127.0.0.1, the page answers there.servewhile running: the same address, still one unit.--stop, thenserve: a port is picked again; it need not be the same one.viewfor that site with no--port: forwards the port the serving machine reported.--port, and taken between pick and bind: exit 1 each time, no address printed, no unit left running.--port, on a free port: served where they are today.Scope
In:
serve's port resolution and its check before starting, where the picked port is kept,viewreading the port back, the messages, anddocs/allod-site-preview.md, whose contract section describes a held port as reported "as serving". Out: which registry a dev VM reads, tracked in allod/archetypes#119; listing the known sites, allod/tools#248.site serve: pick a free port when the registry gives noneto site serve and view: pick a free port when the registry gives none, and report a held port as takenClosing as not planned. The half of this issue that picks a port is dropped; the half that reports a held port as taken continues as allod/tools#252.
What was built
Pull request allod/tools#251 implemented this issue as written:
servepicked a free port for a site with none, kept it in the unit's environment, retried once, andviewread the port back from the VM. It was tested, measured on a dev VM, and reviewed. It is closed unmerged.What it cost
Picking a port saves one line in the registry, once per site. To save that line the change had to solve four problems the fixed port does not have:
viewhad to ask the VM and act on the answer. A VM then chooses which port the hypervisor listens on.viewprints the address,sshrefuses the forward, and every retry reaches the same port because the unit is still running.preview_port.The decision
A site is served on the port the registry gives it, or on
--port. A site with neither keeps today's refusal, which already says to add apreview_port. The inventory's own check refuses a registry where two sites share a port or one is out of range, so keeping ports unique is enforced, not left to memory. With a fixed port the hypervisor takes no value from the VM.What went wrong in the process
The issue was implemented before anyone asked what the pick was for. Of the two situations it names, a machine reading the wrong registry is fixed by allod/archetypes#119, which leaves only a new site with no port yet. That question belonged before the first line of code, not after the pull request.
What continues
allod/tools#252: before starting a unit,
serveconnects to the port once, and refuses if anything answers.Closed as not planned.