Start a process in background and wait Golang [4 Methods]


Written by - Deepak Prasad

In this tutorial we will explore different methods and functions which we can use in golang to execute a process in background and then wait for it to complete.

 

Method-1: Using Wait() method

We can use the Start method of the exec.Cmd struct to start a process in the background and the Wait method to wait for it to complete. Here's an example of how we can use these methods to start a process in the background and wait for it to complete:

package main

import (
	"fmt"
	"os/exec"
)

func main() {
	// Start the process in the background
	cmd := exec.Command("sleep", "60")
	err := cmd.Start()
	if err != nil {
		fmt.Printf("Error: %v\n", err)
		return
	}
	fmt.Printf("Process started with PID: %d\n", cmd.Process.Pid)

	// Wait for the process to complete
	err = cmd.Wait()
	if err != nil {
		fmt.Printf("Error: %v\n", err)
	}
	fmt.Println("Process completed.")
}

In this example the exec.Command("sleep","60") creates a command object to execute the "sleep" command with argument "60", which will sleep for 60 seconds. The cmd.Start() method is used to start the process in the background. Then the cmd.Wait() method is used to wait for the process to complete.

Please note that the Wait method will wait for the process to finish and it will return any error encountered while waiting. If you want to wait for the process to finish and get the process's return code, you can use Wait() method instead of Run() method.

Output:

# go run main.go 
Process started with PID: 17458
Process completed.

 

Method-2: Using exec.CommandContext() function

We can also use the exec.CommandContext function along with the context.Background() and context.WithCancel functions to send a process to background and then wait for it to complete.

package main

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

func main() {
	// Create a background context
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	// Start the process in the background
	cmd := exec.CommandContext(ctx, "sleep", "10")
	err := cmd.Start()
	if err != nil {
		fmt.Printf("Error: %v\n", err)
		return
	}
	fmt.Printf("Process started with PID: %d\n", cmd.Process.Pid)

	// Wait for the process to complete
	err = cmd.Wait()
	if err != nil {
		fmt.Printf("Error: %v\n", err)
	}
	fmt.Println("Process completed.")
}

In this example, it creates a background context using context.Background() and a cancel function using context.WithCancel(context.Background()). The cancel function is used to cancel the context and stop the process if needed. The exec.CommandContext function is used to create the command and pass the background context to it.

Output:

# go run main.go 
Process started with PID: 18199
Process completed.

 

Method-3: Using goroutine

We have a gem in golang known as goroutine which can also help us achieve this magic.

package main

import (
	"fmt"
	"os/exec"
)

func main() {
	// Start the process in a goroutine
	done := make(chan error)
	go func() {
		cmd := exec.Command("sleep", "60")
		err := cmd.Start()
		if err != nil {
			done <- err
			return
		}
		fmt.Printf("Process started with PID: %d\n", cmd.Process.Pid)
		done <- cmd.Wait()
	}()

	// Wait for the goroutine to finish
	err := <-done
	if err != nil {
		fmt.Printf("Error: %v\n", err)
	}
	fmt.Println("Process completed.")
}

This example starts the process in a goroutine using the go keyword, so the process runs in the background. Then the code creates a channel done that is used to wait for the goroutine to finish and returns any error it encountered. Then it waits for the goroutine to finish using err := <-done and if there is any error, it prints that error.

Output:

# go run main.go 
Process started with PID: 18756
Process completed.

 

Method-4: Using sync.WaitGroup()

We can also use a sync.WaitGroup to start a process in the background and wait for it to complete. You can read more about this function at Golang WaitGroup Complete Tutorial

package main

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

func main() {
	var wg sync.WaitGroup
	wg.Add(1)
	go func() {
		defer wg.Done()
		cmd := exec.Command("sleep", "10")
		err := cmd.Start()
		if err != nil {
			fmt.Printf("Error: %v\n", err)
			return
		}
		fmt.Printf("Process started with PID: %d\n", cmd.Process.Pid)
		err = cmd.Wait()
		if err != nil {
			fmt.Printf("Error: %v\n", err)
		}
	}()
	wg.Wait()
	fmt.Println("Process completed.")
}

In this example, it creates a WaitGroup variable wg and adds 1 to it using wg.Add(1) to indicate that there is 1 goroutine that needs to be waited on. Then it starts a goroutine using the go keyword. Inside the goroutine, it starts the process using exec.Command("sleep", "10"). Then it calls wg.Done() at the end of the goroutine to indicate that the goroutine has finished. At the end of the main function, it calls wg.Wait() which will wait until all goroutines have finished.

Output:

# go run main.go 
Process started with PID: 19393
Process completed.

 

Summary

There are many ways to start a process in background and then wait for it to complete, also get the exit status of the background process and process the return value. Here are some of the functions which we covered or which are possible:

  • Using the Start and Wait methods of the exec.Cmd struct.
  • Using the exec.CommandContext function along with the context.Background() and context.WithCancel functions.
  • Using the go keyword to start a goroutine that runs the command, and then using a channel to wait for the goroutine to finish.
  • Using sync.WaitGroup function

 

Views: 127

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 reach out to him on his LinkedIn profile or join on Facebook page.

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