join waits for the speculative dial to finish and returns the result. The caller owns the returned conn (or nothing on error) and is responsible for closing it. join() must be called at most once and must not be interleaved with abandon().
(ctx context.Context)
| 578 | // for closing it. join() must be called at most once and must not be |
| 579 | // interleaved with abandon(). |
| 580 | func (s *speculativeUpstreamTLS) join(ctx context.Context) (*tls.Conn, error) { |
| 581 | var ( |
| 582 | conn *tls.Conn |
| 583 | joinErr error |
| 584 | ) |
| 585 | s.settled.Do(func() { |
| 586 | select { |
| 587 | case r := <-s.done: |
| 588 | s.cancel() // free the derived ctx; no-op if dial already returned |
| 589 | conn, joinErr = r.conn, r.err |
| 590 | case <-ctx.Done(): |
| 591 | // Parent ctx expired; make sure the dial goroutine unblocks. |
| 592 | s.cancel() |
| 593 | // Drain the pending result so the goroutine can exit cleanly. |
| 594 | r := <-s.done |
| 595 | if r.conn != nil { |
| 596 | _ = r.conn.Close() |
| 597 | } |
| 598 | joinErr = ctx.Err() |
| 599 | } |
| 600 | }) |
| 601 | return conn, joinErr |
| 602 | } |
| 603 | |
| 604 | // abandon cancels the in-flight dial and closes the resulting conn if the |
| 605 | // dial had already succeeded. Safe to call multiple times. After abandon() |