func sendConcurrentRequests()

in client/concurrency.go [112:173]


func sendConcurrentRequests(sendFn func() error) error {
	// Get a benchmark for the time it takes for a single request
	singleReqTime, singleReqErr := timeExecution(func() error {
		return sendFn()
	})
	if singleReqErr != nil {
		return fmt.Errorf("concurrent validation unable to send single request to benchmark response time: %v", singleReqErr)
	}

	minWait := 1 * time.Second
	if singleReqTime < minWait {
		return fmt.Errorf("concurrent validation requires a function that waits at least %s before responding, function responded in %s", minWait, singleReqTime)
	}
	log.Printf("Single request response time benchmarked, took %s for 1 request", singleReqTime)

	// Get a benchmark for the time it takes for concurrent requests
	const numConReqs = 10
	log.Printf("Starting %d concurrent workers to send requests", numConReqs)

	type workerResponse struct {
		id  int
		err error
	}
	var wg sync.WaitGroup
	respCh := make(chan workerResponse, numConReqs)
	conReqTime, _ := timeExecution(func() error {
		for i := 0; i < numConReqs; i++ {
			wg.Add(1)
			go func(id int) {
				defer wg.Done()
				err := sendFn()
				respCh <- workerResponse{id: id, err: err}
			}(i)
		}

		wg.Wait()
		return nil
	})

	maybeErrMessage := ""
	for i := 0; i < numConReqs; i++ {
		resp := <-respCh
		if resp.err != nil {
			maybeErrMessage += fmt.Sprintf("error #%d: %v\n", i, resp.err)
		} else {
			log.Printf("Worker #%d done", resp.id)
		}
	}

	if maybeErrMessage != "" {
		return fmt.Errorf("at least one concurrent request failed:\n%s", maybeErrMessage)
	}

	// Validate that the concurrent requests were handled faster than if all
	// the requests were handled serially, using the single request time
	// as a benchmark. Some buffer is provided by doubling the single request time.
	if conReqTime > 2*singleReqTime {
		return fmt.Errorf("function took too long to complete %d concurrent requests. %d concurrent request time: %s, single request time: %s", numConReqs, numConReqs, conReqTime, singleReqTime)
	}
	log.Printf("Concurrent request response time benchmarked, took %s for %d requests", conReqTime, numConReqs)
	return nil
}