Kaynağa Gözat

provide feedback on connection-building errors

since connection building is on-demand it isn't directly in the
execution flow of NewPool() or Pool.Send(). that meant errors there were
getting quietly swallowed, and Pool.Send would just come up with a
timeout.

this change tracks the last build error for a pool and its timestamp,
and makes Pool.Send return that error if it occurred while we were
waiting.
Travis J Parker 10 yıl önce
ebeveyn
işleme
2f9f07f2e9
1 değiştirilmiş dosya ile 21 ekleme ve 9 silme
  1. 21 9
      pool.go

+ 21 - 9
pool.go

@@ -13,13 +13,14 @@ import (
 )
 
 type Pool struct {
-	addr    string
-	auth    smtp.Auth
-	max     int
-	created int
-	clients chan *client
-	rebuild chan struct{}
-	mut     *sync.Mutex
+	addr         string
+	auth         smtp.Auth
+	max          int
+	created      int
+	clients      chan *client
+	rebuild      chan struct{}
+	mut          *sync.Mutex
+	lastBuildErr *timestampedErr
 }
 
 type client struct {
@@ -27,6 +28,11 @@ type client struct {
 	failCount int
 }
 
+type timestampedErr struct {
+	err error
+	ts  time.Time
+}
+
 const maxFails = 4
 
 var ErrTimeout = errors.New("timed out")
@@ -134,6 +140,7 @@ func (p *Pool) makeOne() {
 			if c, err := p.build(); err == nil {
 				p.clients <- c
 			} else {
+				p.lastBuildErr = &timestampedErr{err, time.Now()}
 				p.dec()
 			}
 		}
@@ -215,7 +222,7 @@ func (p *Pool) maybeReplace(err error, c *client) {
 	p.replace(c)
 	return
 
-	shutdown:
+shutdown:
 	p.dec()
 	c.Quit()
 	c.Close()
@@ -223,10 +230,15 @@ func (p *Pool) maybeReplace(err error, c *client) {
 
 // Send sends an email via a connection pulled from the Pool. The timeout may
 // be <0 to indicate no timeout. Otherwise reaching the timeout will produce
-// ErrTimeout.
+// and error building a connection that occurred while we were waiting, or
+// otherwise ErrTimeout.
 func (p *Pool) Send(e *Email, timeout time.Duration) (err error) {
+	start := time.Now()
 	c := p.get(timeout)
 	if c == nil {
+		if p.lastBuildErr != nil && start.Before(p.lastBuildErr.ts) {
+			return p.lastBuildErr.err
+		}
 		return ErrTimeout
 	}