mirror of
https://github.com/tiennm99/keepalive.git
synced 2026-10-11 03:13:31 +00:00
fix(couchbase): improve readiness timeout
This commit is contained in:
1 parent
6b0c2f5a4c
commit
0ad7fbebfc
5 files changed
+50
-3
No files matched your search
@@ -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.
|
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
|
## Adding a new adapter
|
||||||
|
|
||||||
1. Create `adapter/<name>.go`.
|
1. Create `adapter/<name>.go`.
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ func (a *couchbaseAdapter) Connect(ctx context.Context) error {
|
|||||||
}
|
}
|
||||||
b := cluster.Bucket(a.bucket)
|
b := cluster.Bucket(a.bucket)
|
||||||
if err := b.WaitUntilReady(a.readyTimeout, &gocb.WaitUntilReadyOptions{Context: ctx}); err != nil {
|
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 {
|
if err := a.ensureScopeAndCollection(ctx, b); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -9,7 +9,16 @@ import (
|
|||||||
"github.com/couchbase/gocb/v2"
|
"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 {
|
func (a *couchbaseAdapter) ensureBucket(ctx context.Context, cluster *gocb.Cluster) error {
|
||||||
if a.bucketRAMQuotaMB == 0 {
|
if a.bucketRAMQuotaMB == 0 {
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package adapter
|
package adapter
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"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) {
|
func TestCouchbaseFactoryRejectsInvalidReadyTimeout(t *testing.T) {
|
||||||
_, err := New("couchbase", Config{
|
_, err := New("couchbase", Config{
|
||||||
"connection_string": "couchbases://cb.example.com",
|
"connection_string": "couchbases://cb.example.com",
|
||||||
@@ -43,3 +64,18 @@ func TestCouchbaseFactoryRejectsInvalidReadyTimeout(t *testing.T) {
|
|||||||
t.Fatal("New returned nil error")
|
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
|
bucket_name: keepalive
|
||||||
scope_name: _default
|
scope_name: _default
|
||||||
collection_name: _default
|
collection_name: _default
|
||||||
ready_timeout: 30s
|
ready_timeout: 2m
|
||||||
# Optional. Set only when this user can create a missing bucket.
|
# Optional. Set only when this user can create a missing bucket.
|
||||||
# bucket_ram_quota_mb: 128
|
# bucket_ram_quota_mb: 128
|
||||||
Reference in new issue
Block a user