How to PROPERLY kill a process in Golang? [SOLVED]


GO, GOLANG Solutions

In this tutorial we will cover different scenarios to kill a process using golang code. We will use different in-built functions to achieve this requirement.

 

Method-1: Kill a process using Process.Signal()

In this code we start a process using exec.Command() and then will kill the same process using Process.Signal() function. For example, we can use syscall.SIGTERM to send the SIGTERM signal, which is the default signal sent by the kill command. This signal can be caught by the process and it can perform cleanup before exiting.

package main

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

func main() {
	cmd := exec.Command("sleep", "100")
	err := cmd.Start()
	if err != nil {
		fmt.Println(err)
		return
	}

	fmt.Println("Process started with PID:", cmd.Process.Pid)

	// Kill the process after 5 seconds
	<-time.After(5 * time.Second)
	err = cmd.Process.Kill()
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println("Process killed with PID:", cmd.Process.Pid)
}

We can use the Process.Signal method, the process can catch this signal and perform any cleanup before exiting.

Output:

# go run main.go 
Process started with PID: 4538
Process killed with PID: 4538

 

Method-2: Kill parent and all child processes using syscall.Kill()

If we have a requirement to kill the parent and all it's child process then this can also be achieved by using the os.FindProcess function to find the parent process, and then use the syscall.Kill function to send a signal to the parent process and all its child processes.

package main

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

func main() {
	// Generate a parent process
	cmd := exec.Command("sh", "-c", "ping google.com -c 5 & ping yahoo.com -c 5 &")
	cmd.Start()
	fmt.Printf("Parent PID: %d\n", cmd.Process.Pid)

	//listing the child process
	output, _ := exec.Command("ps", "-o", "pid", "-C", "ping").Output()
	fields := strings.Fields(string(output))
	for i := 1; i < len(fields); i++ {
		fmt.Printf("PID of ping: %s\n", fields[i])
	}

	// Kill the parent and child process
	cmd.Process.Kill()
}

This program creates a parent process using the exec.Command function, it runs sh -c "ping google.com -c 5 & ping yahoo.com -c 5 &" command which will ping google.com and yahoo.com five times each in background. Then it uses the ps -o pid -C ping command to list the child process. It filters the output based on command name "ping" using -C option, and using strings.Fields(string(output)) function to split the output into individual fields. Finally, it kills the parent and child process using the cmd.Process.Kill() function.

Output:

# go run main.go 
Parent PID: 12307
PID of ping: 12309
PID of ping: 12310

Also in other terminal we can see the ping process running with same PIDs

~]# ps -ef | grep ping
root       12309       1  0 22:39 pts/0    00:00:00 ping google.com -c 5
root       12310       1  0 22:39 pts/0    00:00:00 ping yahoo.com -c 5
root       12328    5835  0 22:39 pts/1    00:00:00 grep --color=auto ping

 

Method-3: Killing a process by name instead of PID

In this example code we will kill process by name instead of their pid by using pkill()

package main

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

func KillProcessByName(name string) error {
	// Get the process information by name
	output, _ := exec.Command("ps", "-o", "pid,comm", "-C", name).Output()
	lines := strings.Split(string(output), "\n")

	for i, line := range lines {
		if i == 0 {
			continue
		}
		fields := strings.Fields(line)
		if len(fields) < 2 {
			continue
		}
		fmt.Printf("Killing process: %s (PID: %s)\n", fields[1], fields[0])
		// Kill the process
		exec.Command("pkill", "-f", fields[0]).Run()
	}
	return nil
}

func main() {
	// Generate a child process
	cmd := exec.Command("sh", "-c", "ping google.com -c 5 & ping yahoo.com -c 5 &")
	cmd.Start()
	fmt.Printf("Child PID: %d\n", cmd.Process.Pid)

	// Kill the child process by name
	err := KillProcessByName("ping")
	if err != nil {
		fmt.Printf("Error: %v\n", err)
	}
}

Explanation:

  • The KillProcessByName(name string) function is defined, which takes the name of the process as an input.
  • Inside the function, it runs the command ps -o pid,comm -C name which lists the process information based on the command name. The -o option is used to specify the output format, and the pid,comm specifies that the output should show the process ID and command name. The -C option is used to filter the process based on command name, in this case name.
  • The output of the command is stored in the output variable, which is then split into multiple lines using strings.Split(string(output), "\n") function.
  • The code then iterates over the lines, for each line it uses strings.Fields(line) function to split the line into individual fields. The first field is the process ID, the second field is the process name.
  • It then prints the process name and PID before killing it using the pkill command for each of them. The pkill command sends the SIGKILL signal to the process, which will forcefully terminate it.
  • If there is any error it will be returned otherwise it returns nil.

Output:

# go run main.go 
Child PID: 15582
Killing process: ping (PID: 15584)
Killing process: ping (PID: 15585)

 

Summary

In Golang, we have several options to kill a process, such as:

  • The Kill method on the Cmd struct returned by the exec.Command function sends the SIGKILL signal to the process, which cannot be caught or ignored and will force the process to exit immediately.
  • The Process.Signal method can be used to send a specific signal to the process. For example, you can use syscall.SIGTERM to send the SIGTERM signal, which is the default signal sent by the kill command. This signal can be caught by the process and it can perform cleanup before exiting.
  • The Process.Kill method is similar to Kill method of Cmd struct but it uses the underlying syscall.Kill function.

 

Further Reading

os/signal - Go Packages
syscall - Go Packages

 

Deepak Prasad

Deepak Prasad

He is the founder of GoLinuxCloud and brings over a decade of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive experience, he excels in various domains, from development to DevOps, Networking, and Security, ensuring robust and efficient solutions for diverse projects. You can connect with him on his LinkedIn profile.

Can't find what you're searching for? Let us assist you.

Enter your query below, and we'll provide instant results tailored to your needs.

If my articles on GoLinuxCloud has helped you, kindly consider buying me a coffee as a token of appreciation.

Buy GoLinuxCloud a Coffee

For any other feedbacks or questions you can send mail to admin@golinuxcloud.com

Thank You for your support!!

Leave a Comment