Skip to content

Latest commit

 

History

History
136 lines (106 loc) · 2.25 KB

File metadata and controls

136 lines (106 loc) · 2.25 KB

Concurrency » Barrier

Description

The purpose of this pattern is to collect all the results from different functions and goroutines before pass.

Implementation

In this implementation we'll GET some urls (often used for testing purpose). According to pattern description we will output somethine just after both request have been received a response.

func main() {
	barrier(
		"http://httpbin.org/headers",
		"http://httpbin.org/user-agent",
	)
}

This implementation is very idiomatic and uses go keyword. This keyword will start new gorouting with function makeRequest. Also, this function contains a channel called in.

func barrier(urls ...string) {
	numOfRequsts := len(urls)

	in := make(chan Response, numOfRequsts)
	defer close(in)

	responses := make([]Response, numOfRequsts)

	for _, uri := range urls {
		go makeRequest(
			in,
			uri,
		)
	}

  // …
}

Instead, makeRequest function get the content, makes a covertion to string and return to channel everythin.

func makeRequest(out chan<- Response, url string) {
	// …

	resp, err := client.Get(url)
	byt, err := ioutil.ReadAll(resp.Body)
	res.Resp = string(byt)
	out <- res

	// …
}

Here the complete solution:

var timeout int = 5000

type Response struct {
	Err  error
	Resp string
}

func barrier(urls ...string) {
	numOfRequsts := len(urls)

	in := make(chan Response, numOfRequsts)
	defer close(in)

	responses := make([]Response, numOfRequsts)

	for _, uri := range urls {
		go makeRequest(
			in,
			uri,
		)
	}

	var hasError bool
	for i := 0; i < numOfRequsts; i++ {
		resp := <-in
		if resp.Err != nil {
			fmt.Println("ERROR: ", resp.Err)
			hasError = true
		}
		responses[i] = resp
	}

	if !hasError {
		for _, resp := range responses {
			fmt.Println(resp.Resp)
		}
	}
}

func makeRequest(out chan<- Response, url string) {
	res := Response{}
	client := http.Client{
		Timeout: time.Duration(time.Duration(timeout) * time.Millisecond),
	}

	resp, err := client.Get(url)
	if err != nil {
		res.Err = err
		out <- res
		return
	}

	byt, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		res.Err = err
		out <- res
		return
	}

	res.Resp = string(byt)
	out <- res
}

func main() {
	barrier(
		"http://httpbin.org/headers",
		"http://httpbin.org/user-agent",
	)
}