Repository: gomodule/redigo (go)

Issue:
Pool fails to manage number of open connection?
I've got many context deadline exceeded error from Pool.GetContext.

I suspect it fails to manage number of open connection.
It acquires from p.ch here
https://github.com/gomodule/redigo/blob/6f8b8987f003d0b10dd72673c477b054c9189d2c/redis/pool.go#L385
but should we release it back to p.ch here?
https://github.com/gomodule/redigo/blob/6f8b8987f003d0b10dd72673c477b054c9189d2c/redis/pool.go#L390

otherwise available items in p.ch would decrease and eventually couldn't get new one?


Pull request description:
fix: open connection count
This commit releases back the connection in the special
case, so that correct count is always maintained.

Closes #520 

Patch:
diff --git a/redis/pool.go b/redis/pool.go
index fbb8e5b..b74e469 100644
--- a/redis/pool.go
+++ b/redis/pool.go
@@ -377,6 +377,7 @@ func (p *Pool) waitVacantConn(ctx context.Context) (waited time.Duration, err er
 		// because `select` picks a random `case` if several of them are "ready".
 		select {
 		case <-ctx.Done():
+			p.ch <- struct{}{}
 			return 0, ctx.Err()
 		default:
 		}


Test patch:
diff --git a/redis/pool_test.go b/redis/pool_test.go
index a8efa51..b8cd358 100644
--- a/redis/pool_test.go
+++ b/redis/pool_test.go
@@ -825,6 +825,32 @@ func TestWaitPoolGetContext(t *testing.T) {
 	defer c.Close()
 }
 
+func TestWaitPoolGetContextIssue520(t *testing.T) {
+	d := poolDialer{t: t}
+	p := &redis.Pool{
+		MaxIdle:   1,
+		MaxActive: 1,
+		Dial:      d.dial,
+		Wait:      true,
+	}
+	defer p.Close()
+	ctx1, cancel1 := context.WithTimeout(context.Background(), 1*time.Nanosecond)
+	defer cancel1()
+	c, err := p.GetContext(ctx1)
+	if err != context.DeadlineExceeded {
+		t.Fatalf("GetContext returned %v", err)
+	}
+	defer c.Close()
+
+	ctx2, cancel2 := context.WithCancel(context.Background())
+	defer cancel2()
+	c2, err := p.GetContext(ctx2)
+	if err != nil {
+		t.Fatalf("Get context returned %v", err)
+	}
+	defer c2.Close()
+}
+
 func TestWaitPoolGetContextWithDialContext(t *testing.T) {
 	d := poolDialer{t: t}
 	p := &redis.Pool{