github.com/iron-io/functions@v0.0.0-20180820112432-d59d7d1c40b2/test/fnlb-test-harness/main.go (about) 1 package main 2 3 import ( 4 "encoding/json" 5 "flag" 6 "fmt" 7 "io/ioutil" 8 "log" 9 "net/http" 10 "strings" 11 "time" 12 ) 13 14 type execution struct { 15 DurationSeconds float64 16 Hostname string 17 node string 18 body string 19 responseSeconds float64 20 } 21 22 var ( 23 lbHostPort, nodesStr, route string 24 numExecutions, maxPrime, numLoops int 25 nodes []string 26 nodesByContainerId map[string]string = make(map[string]string) 27 verbose bool 28 ) 29 30 func init() { 31 flag.StringVar(&lbHostPort, "lb", "localhost:8081", "host and port of load balancer") 32 flag.StringVar(&nodesStr, "nodes", "localhost:8080", "comma-delimited list of nodes (host:port) balanced by the load balancer (needed to discover container id of each)") 33 flag.StringVar(&route, "route", "/r/primesapp/primes", "path representing the route to the primes function") 34 flag.IntVar(&numExecutions, "calls", 100, "number of times to call the route") 35 flag.IntVar(&maxPrime, "max", 1000000, "maximum number to search for primes (higher number consumes more memory)") 36 flag.IntVar(&numLoops, "loops", 1, "number of times to execute the primes calculation (ex: 'loops=2' means run the primes calculation twice)") 37 flag.BoolVar(&verbose, "v", false, "true for more verbose output") 38 flag.Parse() 39 40 if maxPrime < 3 { 41 log.Fatal("-max must be 3 or greater") 42 } 43 if numLoops < 1 { 44 log.Fatal("-loops must be 1 or greater") 45 } 46 47 nodes = strings.Split(nodesStr, ",") 48 } 49 50 func executeFunction(hostPort, path string, max, loops int) (execution, error) { 51 var e execution 52 53 start := time.Now() 54 resp, err := http.Get(fmt.Sprintf("http://%s%s?max=%d&loops=%d", hostPort, path, max, loops)) 55 e.responseSeconds = time.Since(start).Seconds() 56 if err != nil { 57 return e, err 58 } 59 defer resp.Body.Close() 60 if resp.StatusCode != http.StatusOK { 61 return e, fmt.Errorf("function returned status code: %d", resp.StatusCode) 62 } 63 64 body, err := ioutil.ReadAll(resp.Body) 65 if err != nil { 66 return e, err 67 } 68 69 err = json.Unmarshal(body, &e) 70 if err != nil { 71 e.body = string(body) // set the body in the execution so that it is available for logging 72 return e, err 73 } 74 e.node = nodesByContainerId[e.Hostname] 75 76 return e, nil 77 } 78 79 func invokeLoadBalancer(hostPort, path string, numExecutions, max, loops int) { 80 executionsByNode := make(map[string][]execution) 81 fmt.Printf("All primes will be calculated up to %d, a total of %d time(s)\n", maxPrime, numLoops) 82 fmt.Printf("Calling route %s %d times (through the load balancer)...\n", route, numExecutions) 83 84 for i := 0; i < numExecutions; i++ { 85 e, err := executeFunction(hostPort, path, max, loops) 86 if err == nil { 87 if ex, ok := executionsByNode[e.node]; ok { 88 executionsByNode[e.node] = append(ex, e) 89 } else { 90 // Create a slice to contain the list of executions for this host 91 executionsByNode[e.node] = []execution{e} 92 } 93 if verbose { 94 fmt.Printf(" %s in-function duration: %fsec, response time: %fsec\n", e.node, e.DurationSeconds, e.responseSeconds) 95 } 96 } else { 97 fmt.Printf(" Ignoring failed execution on node %s: %v\n", e.node, err) 98 fmt.Printf(" JSON: %s\n", e.body) 99 } 100 } 101 102 fmt.Println("Results (executions per node):") 103 for node, ex := range executionsByNode { 104 fmt.Printf(" %s %d\n", node, len(ex)) 105 } 106 } 107 108 func discoverContainerIds() { 109 // Discover the Docker hostname of each node; create a mapping of hostnames to host/port. 110 // This is needed because IronFunctions doesn't make the host/port available to the function (as of Mar 2017). 111 fmt.Println("Discovering container ids for every node (use Docker's HOSTNAME env var as a container id)...") 112 for _, s := range nodes { 113 if e, err := executeFunction(s, route, 100, 1); err == nil { 114 nodesByContainerId[e.Hostname] = s 115 fmt.Printf(" %s %s\n", s, e.Hostname) 116 } else { 117 fmt.Printf(" Ignoring host %s which returned error: %v\n", s, err) 118 fmt.Printf(" JSON: %s\n", e.body) 119 } 120 } 121 } 122 123 func main() { 124 discoverContainerIds() 125 invokeLoadBalancer(lbHostPort, route, numExecutions, maxPrime, numLoops) 126 }