With gokrazy/gokrazy#106, we're sending a TERM signal to service
processes and their immediate children. Service processes are being
waited on by `cmd.Wait()`, which will reap any kernel state associated
with it. However, its child processes don't necessarily get reaped
(depending on whether its parent had time to clean up before exiting).
With this change, we explicitly wait for everything in the service
process group to exit and prevent zombies.
Currently, rebooting/upgrading the instance sends a TERM signal to all
running services, waits 1 second and then reboots. Processes that take
longer to cleanly stop can't do so.
Instead, give each service up to 15s to do a clean shutdown. Reboot 15s
after the command is sent, or after all services are stopped, whichever
comes first.
To make it easier to kill entire process tree for a service, create a
per-service process group. Stopping the service can be done by sending a
single signal to the process group.
Create a /log endpoint for streaming stdout/stderr logs for processes.
Replace status page stdout/stderr to call into /log to stream logs and
live update page.