Skip to content

Instantly share code, notes, and snippets.

@hackintoshrao
Created February 24, 2017 03:12
Show Gist options
  • Select an option

  • Save hackintoshrao/a856378dad60bd0b0890b2883aa08b59 to your computer and use it in GitHub Desktop.

Select an option

Save hackintoshrao/a856378dad60bd0b0890b2883aa08b59 to your computer and use it in GitHub Desktop.
Leaky server with the instrumentation for
package main
import (
"fmt"
"log"
"net/http"
"runtime"
"runtime/debug"
"runtime/pprof"
"strconv"
)
// get the count of number of go routines in the system.
func countGoRoutines() int {
return runtime.NumGoroutine()
}
// respond with number of go routines in the system.
func getGoroutinesCountHandler(w http.ResponseWriter, r *http.Request) {
// Get the count of number of go routines running.
count := countGoRoutines()
w.Write([]byte(strconv.Itoa(count)))
}
// respond with the stack trace of the system.
func getStackTraceHandler(w http.ResponseWriter, r *http.Request) {
stack := debug.Stack()
w.Write(stack)
pprof.Lookup("goroutine").WriteTo(w, 2)
}
// function to add an array of numbers.
func sum(s []int, c chan int) {
sum := 0
for _, v := range s {
sum += v
}
// writes the sum to the go routines.
c <- sum // send sum to c
}
// HTTP handler for /sum
func sumConcurrent(w http.ResponseWriter, r *http.Request) {
s := []int{7, 2, 8, -9, 4, 0}
c1 := make(chan int)
c2 := make(chan int)
// spin up a goroutine.
go sum(s[:len(s)/2], c1)
// spin up a goroutine.
go sum(s[len(s)/2:], c2)
// not reading from c2.
// go routine writing to c2 will be blocked.
x := <-c1
// write the response.
fmt.Fprintf(w, strconv.Itoa(x))
}
func main() {
// get the sum of numbers.
http.HandleFunc("/sum", sumConcurrent)
// get the count of number of go routines in the system.
http.HandleFunc("/_count", getGoroutinesCountHandler)
// respond with the stack trace of the system.
http.HandleFunc("/_stack", getStackTraceHandler)
err := http.ListenAndServe(":8001", nil)
if err != nil {
log.Fatal("ListenAndServe: ", err)
}
}
package main
import (
"io/ioutil"
"log"
"net/http"
"strconv"
"sync"
)
const (
leakyServer = "http://localhost:8001"
)
// get the count of the number of go routines in the server.
func getRoutineCount() (int, error) {
body, err := getReq("/_count")
if err != nil {
return -1, err
}
count, err := strconv.Atoi(string(body))
if err != nil {
return -1, err
}
return count, nil
}
// Send get request and return the repsonse body.
func getReq(endPoint string) ([]byte, error) {
response, err := http.Get(leakyServer + endPoint)
if err != nil {
return []byte{}, err
}
defer response.Body.Close()
body, err := ioutil.ReadAll(response.Body)
if err != nil {
return []byte{}, err
}
return body, nil
}
// obtain stack trace of the server.
func getStackTrace() (string, error) {
body, err := getReq("/_stack")
if err != nil {
return "", err
}
return string(body), nil
}
func main() {
// get the number of go routines in the leaky server.
count, err := getRoutineCount()
if err != nil {
log.Fatal(err)
}
log.Printf("\n %d Go routines before the load test in the system.", count)
var wg sync.WaitGroup
// send 50 concurrent request to the leaky endpoint.
for i := 0; i < 50; i++ {
wg.Add(1)
go func() {
defer wg.Done()
_, err = getReq("/sum")
if err != nil {
log.Fatal(err)
}
}()
}
wg.Wait()
// get the cout of number of goroutines in the system after the load test.
count, err = getRoutineCount()
if err != nil {
log.Fatal(err)
}
log.Printf("\n %d Go routines after the load test in the system.", count)
// obtain the stack trace of the system.
trace, err := getStackTrace()
if err != nil {
log.Fatal(err)
}
log.Printf("\nStack trace after the load test : \n %s",trace)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment