mirror of
https://github.com/tiennm99/keepalive.git
synced 2026-09-02 14:20:33 +00:00
fix(couchbase): improve readiness timeout
This commit is contained in:
@@ -96,6 +96,8 @@ On startup each adapter initializes the minimum resource it owns, then every tic
|
||||
|
||||
Each configured service starts independently. If one service cannot connect, it logs the error and retries without stopping other services in the same deployment.
|
||||
|
||||
For hosted Couchbase/Capella clusters, `ready_timeout` defaults to `2m`. If Couchbase still reports `CONNECTION_ERROR`, check the connection string, bucket name, database user permissions, and Capella allowed IP/network access.
|
||||
|
||||
## Adding a new adapter
|
||||
|
||||
1. Create `adapter/<name>.go`.
|
||||
|
||||
@@ -93,7 +93,7 @@ func (a *couchbaseAdapter) Connect(ctx context.Context) error {
|
||||
}
|
||||
b := cluster.Bucket(a.bucket)
|
||||
if err := b.WaitUntilReady(a.readyTimeout, &gocb.WaitUntilReadyOptions{Context: ctx}); err != nil {
|
||||
return err
|
||||
return a.bucketReadyError(err)
|
||||
}
|
||||
if err := a.ensureScopeAndCollection(ctx, b); err != nil {
|
||||
return err
|
||||
|
||||
@@ -9,7 +9,16 @@ import (
|
||||
"github.com/couchbase/gocb/v2"
|
||||
)
|
||||
|
||||
const defaultCouchbaseReadyTimeout = 30 * time.Second
|
||||
const defaultCouchbaseReadyTimeout = 2 * time.Minute
|
||||
|
||||
func (a *couchbaseAdapter) bucketReadyError(err error) error {
|
||||
return fmt.Errorf(
|
||||
"bucket %q was not ready after %s: %w; check bucket_name, connection_string, database user permissions, and Capella allowed IP/network access; increase ready_timeout if the cluster or bucket was just created",
|
||||
a.bucket,
|
||||
a.readyTimeout,
|
||||
err,
|
||||
)
|
||||
}
|
||||
|
||||
func (a *couchbaseAdapter) ensureBucket(ctx context.Context, cluster *gocb.Cluster) error {
|
||||
if a.bucketRAMQuotaMB == 0 {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package adapter
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
@@ -29,6 +31,25 @@ func TestCouchbaseFactoryParsesInitializationOptions(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestCouchbaseFactoryUsesHostedReadyTimeoutDefault(t *testing.T) {
|
||||
a, err := New("couchbase", Config{
|
||||
"connection_string": "couchbases://cb.example.com",
|
||||
"username": "user",
|
||||
"password": "pass",
|
||||
"bucket_name": "keepalive",
|
||||
"scope_name": "scope",
|
||||
"collection_name": "collection",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("New returned error: %v", err)
|
||||
}
|
||||
|
||||
got := a.(*couchbaseAdapter)
|
||||
if got.readyTimeout != 2*time.Minute {
|
||||
t.Fatalf("readyTimeout = %s, want 2m", got.readyTimeout)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCouchbaseFactoryRejectsInvalidReadyTimeout(t *testing.T) {
|
||||
_, err := New("couchbase", Config{
|
||||
"connection_string": "couchbases://cb.example.com",
|
||||
@@ -43,3 +64,18 @@ func TestCouchbaseFactoryRejectsInvalidReadyTimeout(t *testing.T) {
|
||||
t.Fatal("New returned nil error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCouchbaseBucketReadyErrorAddsActionableContext(t *testing.T) {
|
||||
cause := errors.New("unambiguous timeout")
|
||||
a := couchbaseAdapter{bucket: "keepalive", readyTimeout: 2 * time.Minute}
|
||||
|
||||
err := a.bucketReadyError(cause)
|
||||
if !errors.Is(err, cause) {
|
||||
t.Fatalf("bucketReadyError does not wrap cause: %v", err)
|
||||
}
|
||||
for _, want := range []string{"keepalive", "2m0s", "Capella allowed IP", "ready_timeout"} {
|
||||
if !strings.Contains(err.Error(), want) {
|
||||
t.Fatalf("bucketReadyError() = %q, want it to contain %q", err, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -25,6 +25,6 @@ services:
|
||||
bucket_name: keepalive
|
||||
scope_name: _default
|
||||
collection_name: _default
|
||||
ready_timeout: 30s
|
||||
ready_timeout: 2m
|
||||
# Optional. Set only when this user can create a missing bucket.
|
||||
# bucket_ram_quota_mb: 128
|
||||
|
||||
Reference in New Issue
Block a user