/*! * Get the next job to run, after sleeping until the time it's supposed * to run. * * @return The next job to run, or nil if the context has been canceled. */ func (jq *JobQueue) Pop(now time.Time, ctx context.Context) *Job { if jq.Empty() { // just wait till the context has been canceled <-ctx.Done() return nil } else { // get next-scheduled job job := heap.Pop(&jq.q).(*Job) // sleep till it's time to run it if now.Before(*job.NextRunTime) { afterChan := time.After(job.NextRunTime.Sub(now)) select { case now = <-afterChan: case <-ctx.Done(): // abort! heap.Push(&jq.q, job) return nil } } // schedule this job's next run job.NextRunTime = nextRunTime(job, now.Add(time.Second)) if job.NextRunTime != nil { heap.Push(&jq.q, job) } // decide whether we really should run this job if job.ShouldRun() { return job } else { // skip this job return jq.Pop(now, ctx) } } }
// Do sends an HTTP request with the provided http.Client and returns an HTTP response. // If the client is nil, http.DefaultClient is used. // If the context is canceled or times out, ctx.Err() will be returned. func Do(ctx context.Context, client *http.Client, req *http.Request) (*http.Response, error) { if client == nil { client = http.DefaultClient } // Request cancelation changed in Go 1.5, see cancelreq.go and cancelreq_go14.go. cancel := canceler(client, req) type responseAndError struct { resp *http.Response err error } result := make(chan responseAndError, 1) go func() { resp, err := client.Do(req) testHookDoReturned() result <- responseAndError{resp, err} }() var resp *http.Response select { case <-ctx.Done(): testHookContextDoneBeforeHeaders() cancel() // Clean up after the goroutine calling client.Do: go func() { if r := <-result; r.resp != nil { testHookDidBodyClose() r.resp.Body.Close() } }() return nil, ctx.Err() case r := <-result: var err error resp, err = r.resp, r.err if err != nil { return resp, err } } c := make(chan struct{}) go func() { select { case <-ctx.Done(): cancel() case <-c: // The response's Body is closed. } }() resp.Body = ¬ifyingReader{resp.Body, c} return resp, nil }