Читать книгу 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.