Skip to content

os/exec: Unable to kill a command on macOS? #27440

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
andreynering opened this issue Sep 1, 2018 · 7 comments
Closed

os/exec: Unable to kill a command on macOS? #27440

andreynering opened this issue Sep 1, 2018 · 7 comments
Labels
FrozenDueToAge WaitingForInfo Issue is not actionable because of missing required information, which needs to be provided.

Comments

@andreynering
Copy link

What version of Go are you using (go version)?

go version go1.11 darwin/amd64

Does this issue reproduce with the latest release?

Yes

What operating system and processor architecture are you using (go env)?

GOARCH="amd64"
GOBIN=""
GOCACHE="/Users/andrey/Library/Caches/go-build"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOOS="darwin"
GOPATH="/Users/andrey/code/andrey/GOPATH"
GOPROXY=""
GORACE=""
GOROOT="/usr/local/Cellar/go/1.11/libexec"
GOTMPDIR=""
GOTOOLDIR="/usr/local/Cellar/go/1.11/libexec/pkg/tool/darwin_amd64"
GCCGO="gccgo"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/27/jbd81kh91cn15gq7sbm7xy580000gp/T/go-build184649496=/tmp/go-build -gno-record-gcc-switches -fno-common"

Reproduce

I think this is specific to macOS. Although I haven't tried the exact script below on another OS, I'm sure I ran similar scripts on Windows and Linux before and it worked fine

Given any long running executable:

package main

import (
	"fmt"
	"net/http"
)

func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "Hello, World!")
	})
	panic(http.ListenAndServe(":8080", nil))
}

Suppose we want to run the program above, but kill it after 5 seconds:

package main

import (
	"context"
	"fmt"
	"os/exec"
	"time"
)

func main() {
	ctx, cancel := context.WithCancel(context.Background())

	go func() {
		time.Sleep(5 * time.Second)
		fmt.Println("Trying to terminate server.go")
		cancel()
	}()

	fmt.Println("Starting command")
	if err := exec.CommandContext(ctx, "go", "run", "server.go").Run(); err != nil {
		panic(err)
	}
	fmt.Println("Terminating command")
}

The script above exits with a panic, but the server keeps running in background

I also tried to kill the process directly, but got the same result:

package main

import (
	"fmt"
	"os"
	"os/exec"
	"time"
)

func main() {
	cmd := exec.Command("go", "run", "./cmd/server/server.go")

	go func() {
		time.Sleep(5 * time.Second)
		fmt.Println("Trying to terminate server.go")
		cmd.Process.Signal(os.Kill)
	}()

	fmt.Println("Starting command")
	if err := cmd.Run(); err != nil {
		panic(err)
	}
	fmt.Println("Terminating command")
}

The interesting fact is that if I press Control+C before those 5 seconds then the server is killed without any problem

@mark-rushakoff
Copy link
Contributor

Is it only when you exec go run? If you go build cmd/server/server.go and then exec the resulting binary, does it behave the same way?

@andreynering
Copy link
Author

@mark-rushakoff It doesn't matter if you run it using go run or go build + ./server. Actually, I think it don't need to be a Go program, can be any long running program

@mirza-s
Copy link

mirza-s commented Sep 2, 2018

For me, this happens only when running with go run on both macOS and Linux.
Running a prebuilt binary works as you would expect.

@crvv
Copy link
Contributor

crvv commented Sep 3, 2018

If you press Control+C, SIGINT will be sent to the process group and all the processes will terminate.

Process.Signal(os.Kill) and Context.cancel() are identical. They both send SIGKILL to the subprocess.

If you use go run server.go, the subprocess is go. server is a subprocess of go.
SIGKILL killed go and leave server running.

@akamensky
Copy link

Same for me, go run and go build both get stuck like that, except that I observe this in Goland IDE (latest version).

It appears that if I keep requesting server that was supposed to be killed eventually it will exit.

@andreynering
Copy link
Author

Sorry, I didn't have the time to try this again. Will do when possible

But indeed, it's possible that I was it was wrong and it happens only for go run

I'm trying to understand an issue on one of my projects, so trying different things to see if I find the problem

@andybons andybons added the WaitingForInfo Issue is not actionable because of missing required information, which needs to be provided. label Sep 4, 2018
@andreynering
Copy link
Author

You're right that this only happen when using go run. The issue I'm facing might be something else

Closing this

@golang golang locked and limited conversation to collaborators Sep 8, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
FrozenDueToAge WaitingForInfo Issue is not actionable because of missing required information, which needs to be provided.
Projects
None yet
Development

No branches or pull requests

7 participants