Peter Björklund

Peter Björklund

in Development

Concurrency in golang

I got a few questions after my last post on golang regarding concurrency. What makes it so easy? I thought I would just give you an example. Below is a simple program that completes a bunch of health checks concurrently.

Do something fun this weekend and Download golang at https://golang.org/ and fiddle with the program below. Let me know what you think.

package main

import (
	"encoding/json"
	"io/ioutil"
	"log"
	"net/http"
	"sync"
)

type healthCheckResult struct {
	Url           string
	HttpStatus    int
	ServiceStatus string `json:"result"`
}

// concurrency example: Health checks
func main() {
	// endpoints to check
	checks := []string{
		"https://api.haaartland.com/health";,
		"https://app.haaartland.com/health";,
	}

	// create a wait group for concurrent tasks
	var wg sync.WaitGroup

	// define nr of tasks to complete
	wg.Add(len(checks))

	// result channel for finished tasks
	checkRes := make(chan *healthCheckResult, len(checks))

	// start a go routine to wait for all tasks to complete
	go func() {
		wg.Wait()       // Blocking waiter until all tasks are completed
		close(checkRes) // close the result channel
	}()

	// start tasks concurrently
	for _, url := range checks {
		go healthCheck(url, checkRes)
	}

	// print results as they become available
	for res := range checkRes {
		wg.Done() // mark task as completed
		log.Printf("%s %d: %s", res.Url, res.HttpStatus, res.ServiceStatus)
	}
}

func healthCheck(url string, checkRes chan *healthCheckResult) {
	res := &healthCheckResult{Url: url, ServiceStatus: "n/a"}

	if httpRes, err := http.Get(url); err != nil {
		checkRes <- res // nothing to do, couldn't reach host

	} else {
		// handle response
		defer httpRes.Body.Close()
		res.HttpStatus = httpRes.StatusCode

		bytes, _ := ioutil.ReadAll(httpRes.Body)
		json.Unmarshal(bytes, res)

		checkRes <- res // send result on channel
	}
}
Do you want to read more like this? Hit subscribe. It’s FREE!