awesome-patterns/concurrency/error_handle/main.go

90 lines
2.4 KiB
Go
Raw Permalink Normal View History

2018-01-22 15:55:07 +03:00
package main
// n general, your concurrent processes should send their
// errors to another part of your program that has complete information
// about the state of your program, and can make a more informed decision about what to do.
import (
"fmt"
"net/http"
)
func main() {
// noErrorHandling()
errorHandling()
}
// Here we create a type that encompasses both the *http.Response and the error
// possible from an iteration of the loop within our goroutine.
type Result struct {
Error error
Response *http.Response
}
func errorHandling() {
// This line returns a channel that can be read from to retrieve results of an iteration of our loop
checkStatus := func(done <-chan interface{}, urls ...string) <-chan Result {
results := make(chan Result)
go func() {
defer close(results)
for _, url := range urls {
var result Result
resp, err := http.Get(url)
// Here we create a Result instance with the Error and Response fields set.
result = Result{Error: err, Response: resp}
select {
case <-done:
2018-01-22 16:16:37 +03:00
// TODO: need to refactor the code, this might be a bug since
// this will never execute.
2018-01-22 15:55:07 +03:00
return
// This is where we write the Result to our channel
case results <- result:
}
}
}()
return results
}
done := make(chan interface{})
defer close(done)
urls := []string{"https://www.google.com", "https://badhost"}
for result := range checkStatus(done, urls...) {
// Here, in our main goroutine, we are able to deal with errors coming out of the
// goroutine started by checkStatus intelligently, and with the full context of the larger program.
if result.Error != nil {
fmt.Printf("error: %v", result.Error)
continue
}
fmt.Printf("Response: %v\n", result.Response.Status)
}
}
func noErrorHandling() {
checkStatus := func(
done <-chan interface{},
urls ...string,
) <-chan *http.Response {
responses := make(chan *http.Response)
go func() {
defer close(responses)
for _, url := range urls {
resp, err := http.Get(url)
if err != nil {
fmt.Println(err)
continue
}
select {
case <-done:
return
case responses <- resp:
}
}
}()
return responses
}
done := make(chan interface{})
defer close(done)
urls := []string{"https://www.google.com", "https://badhost"}
for response := range checkStatus(done, urls...) {
fmt.Printf("Response: %v\n", response.Status)
}
}