Clear a port held by more than one process - #789
Conversation
|
Thanks for tracking this down. The bug reproduces for me: with two PIDs, Two things I ran into while reading it. The loop can report failure on a run that worked. For a forked server, such as Puma or Node in cluster mode, the parent and every worker inherit the listening socket, so they all appear in the LISTEN list. The loop signals the parent first. The parent then tears down its workers, and by the time the loop reaches the worker PIDs they are already gone. The pull request description does not match the code. The description says "Leave the expansion unquoted so that each PID becomes an argument of its own", which is the batched version. The diff uses the loop instead. The commit body is accurate, so it is only the description that has drifted. The unquoted form does trip shellcheck (SC2086). Piping into lsof -ti4TCP:"$1" -sTCP:LISTEN | xargs -r killI checked that with shellcheck 0.11.0 and it is clean. With a stubbed On One last thing worth folding in: the header comment still says "Kills the process running on the provided port", singular, which is the assumption this change exists to correct. |
`clear-port` killed nothing whenever more than one process held the
port:
kill: `453236
785863': not a pid or valid job spec
lsof prints one PID per line, and quoting the result handed the whole
list to kill as a single argument. Pipe the PIDs into xargs so that each
becomes an argument of its own, which also retires the `$?` check that
only ever guarded the empty case.
Batching them into one kill matters as much as unquoting. A forked
server shares its listening socket with every worker, so the parent and
the workers all appear in the LISTEN list, and the parent tears its
workers down as soon as it is signalled. Signalling one PID at a time
would reach those workers after they had already gone and report `No
such process` for a run that did exactly what it set out to do. A single
kill sends every signal without waiting for the parent to reap them in
between.
More than one process is the ordinary case rather than an edge case,
because `lsof -ti4TCP:PORT` matches established connections as well as
listeners, so a browser with the page open is listed alongside the
server it is talking to. `-sTCP:LISTEN` narrows the match to the
listening process, which is both what the script sets out to kill and
what stops the browser being killed once kill starts working.
The pipe into xargs is preferred to an unquoted `$(...)`, which batches
just as well but trips SC2086 and runs kill with no arguments when the
port is free. `-r` covers that last case on GNU xargs, and is a
documented no-op on the BSD xargs that ships with macOS.
170ab6f to
939a270
Compare
|
Thanks Rob, here are the changes:
Let me know if there's anything else you want me to address. |
clear-portkilled nothing when more than one process held the port:lsofprints one PID per line, and quoting the result handed the whole list tokillas a single argument. Piping the PIDs intoxargsgives each one an argument of its own.They go out in a single
killrather than one at a time. A forked server shares its listening socket with every worker, so the parent and the workers all appear in the LISTEN list, and the parent tears its workers down as soon as it is signalled. Signalling one PID at a time would reach those workers after they had already gone and reportNo such processfor a run that worked.More than one process is the ordinary case rather than an edge case, because
lsof -ti4TCP:PORTmatches established connections as well as listeners, so a browser with the page open is listed alongside the server it is talking to.-sTCP:LISTENnarrows the match to the listening process, which is both what the script sets out to kill and what stops the browser being killed oncekillstarts working.The pipe into
xargsis preferred to an unquoted$(...), which batches just as well but trips SC2086 and runskillwith no arguments when the port is free.-rcovers that last case on GNUxargs, and is a documented no-op on the BSDxargsthat ships with macOS.