Around Go: command line · 3 MIN READ

Processes, signals and exit status

Start one Go service, retain its PID, send TERM and wait for its result.

A process has a PID, an exit status and open streams. Starting a service in the background does not detach it from responsibility: keep the PID and wait for completion. These commands assume a local Go project with cmd/api and an available port.

01

Start the binary you can stop directly

Build first, then run the binary itself in the background. $! is the PID of the latest asynchronous command. A background go run process may introduce a build/launcher process, so it is a poor substitute when practicing exact signal ownership.

bash
mkdir -p bin
go build -o ./bin/api ./cmd/api
./bin/api > api.log 2>&1 &
api_pid=$!
printf "API PID: %s\n" "$api_pid"
Read the code

Run the launch only after the build succeeds. Both output streams go to api.log. Record this PID instead of searching all processes by a broad application name or terminating unrelated Go jobs.

02

Inspect the process and the listening port

ps reports process state; kill -0 checks that a PID can be addressed without sending a signal. lsof is a separately installed utility on some systems and can identify a listening socket; it does not prove the HTTP handler returns useful responses.

bash
ps -p "$api_pid" -o pid,etime,args
kill -0 "$api_pid"
lsof -nP -iTCP:8080 -sTCP:LISTEN
Read the code

Check that the socket belongs to the binary you launched. If lsof is missing, use your OS socket inspection tool. A process may exit between any two commands; observation is not a lifetime guarantee.

03

Request shutdown and collect the outcome

TERM lets a cooperative service drain work. wait observes your shell child and reaps it; an if branch can preserve nonzero status without aborting the shell. SIGKILL prevents application cleanup, so use it only after diagnosing an unresponsive process.

bash
kill -TERM "$api_pid"
if wait "$api_pid"; then
    printf "%s\n" "Service exited successfully"
else
    status=$?
    printf "Service exit status: %s\n" "$status"
fi
tail -n 20 api.log
Read the code

A graceful service can return zero. A process terminated by a signal may report a nonzero status; inspect its log and shutdown contract. wait works for children of this shell, not any arbitrary PID from another terminal.

TAKE THIS WITH YOU

Keep the child PID, inspect it, request TERM and wait for the outcome. A listening port, a live process and a successful HTTP response are three different observations.

Check your understanding

What does wait "$api_pid" do for a child started in this shell?

Go to the source

Progress stays in this browser. No account needed.