Читать книгу Practical Go - Amit Saha - Страница 65

Listing 2.8: Handling user signals

Оглавление

// chap2/user-signal/main.go package main import ( "context" "fmt" "io" "os" "os/exec" "os/signal" "time" ) // TODO Insert definition of createContextWithTimeout() as above // TODO Insert definition of setupSignalHandler() as above // TODO Insert definition of executeCommand as above func main() { if len(os.Args) != 3 { fmt.Fprintf(os.Stdout, "Usage: %s <command> <argument>\n", os.Args[0]) os.Exit(1) } command := os.Args[1] arg := os.Args[2] // Implement Step 1 cmdTimeout := 30 * time.Second ctx, cancel := createContextWithTimeout(cmdTimeout) defer cancel() // Implement Step 2 setupSignalHandler(os.Stdout, cancel) // Implement Step 3 err := executeCommand(ctx, command, arg) if err != nil { fmt.Fprintln(os.Stdout, err) os.Exit(1) } }

The main() function starts by checking to see if the expected number of arguments have been specified. Here we implement a basic user interface and expect the application to be executed as ./application sleep 60 where sleep is the command to be executed and 60 is the argument to the command. Then we store the command to be executed and the argument to it in two string variables: – command and arg. The createContextWithTimeout() function is then called with a duration object specifying a 30-second time-out. The function returns a context, ctx, and a context cancellation function, cancel. In the next statement, we call the function in a deferred call.

We then call the setupSignalHandler() function, passing it two parameters: – os.Stdout and the context's cancellation function, cancel .

Finally, we call the executeCommand() function with the context object created, ctx ; the command to execute, command ; and the argument to the command, arg. If there is an error returned, it is printed.

Create a new directory, chap2/user-signal, and initialize a module inside it:

$ mkdir -p chap2/user-signal $ cd chap2/user-signal $ go mod init github.com/username/user-signal

Next, save Listing 2.8 as a new file, main.go, and build it:

$ go build -o application

Considering that the time-out is set to 30 seconds, let's try executing the sleep command with a value for the time to sleep:

% ./application sleep 60 ^CGot signal:interrupt signal: interrupt

We ask the sleep command to sleep for 60 seconds but manually abort it by pressing Ctrl+C. The error message tells us how the command was aborted.

Next, we sleep for 10 seconds:

% ./application sleep 10

As 10 seconds is lower than the context time-out for 30 seconds, it exits cleanly. Finally, let's execute the sleep command for 31 seconds:

% ./listing7 sleep 31 signal: killed

Now we can see that the time-out context kicks in and kills the process.

Practical Go

Подняться наверх