Problem with bucketManager.CreateBucket

Hello! I have a problem with bucketmanager when I changed gocb from v1 to v2.

couchbase: Docker image 6.0.3
gocb SDK v2

opts := gocb.ClusterOptions{
Authenticator: gocb.PasswordAuthenticator{
Username: “Administrator”,
Password: “password”,
},
}
cb, err := gocb.Connect(“couchbase://127.0.0.1”, opts)
if err != nil {
panic(err)
}

bucketsManager := cb.Buckets()

err = bucketsManager.CreateBucket(gocb.CreateBucketSettings{
	BucketSettings: gocb.BucketSettings{
		Name:         "demo1232",
		BucketType:   "membase",
		RAMQuotaMB:   100,
		FlushEnabled: true,
	},
}, nil)
if err != nil {
	fmt.Println(err)
}

Here I got an error: "cluster-level operations not supported due to cluster version"
I searched a lot, but I can’t understand what is the problem right here…

Thank you in advance!

1 Like

@troger_headshot In pre 6.5 clusters you need to open at least one bucket, even if you are only using the cluster-level APIs, because internally only with 6.5+ the server sends us a config at the cluster level… so this is similar to the previous generation SDKs.

1 Like

Hi!
@daschl Thank you for very fast reaction!
How do you mean to open at least one bucket?
And then, how to store this config in bucketManager config struct? Thank you! :slight_smile:

Have the same error on 6.5.1 CE server.

Hi @1110 this is a bug that I’ve raised an issue for https://issues.couchbase.com/browse/GOCBC-879. The problem is that you are calling the function before the cluster is actually connected properly (which happens asynchronously) so it thinks that it doesn’t support the performing operations without a bucket.

There is a workaround for this (against 6.5+) which is to use something like the following before performing any operations: err := cluster.WaitUntilReady(2*time.Second, nil). This will block for a maximum of the time specified returning either a timeout error if the timeout hit or no error if the cluster object connected successfully before the time.

1 Like

Hi @chvck, thanks for the quick response! This workaround seems to work. Is there a similar strategy for obtaining confirmation of the success/failure bucket creation operation?

Hi @1110, I’m not entirely what you’re referring to by “bucket creation” operation. If you mean cluster.Bucket("mybucket") then then bucket.WaitUntilReady also exists and it will return no error or a timeout depending on if the SDK could connect to the bucket or not.

I’m talking about BucketManager.CreateBucket.
bucket.bucket.WaitUntilReady seem doesn’t work. What I’m trying to do is something like this:

c, err := gocb.Connect(opts.Address, gocb.ClusterOptions{
		Username: opts.UserName,
		Password: opts.Password,
	})
	if err != nil {
		t.Fatal(err)
	}
	if err := c.WaitUntilReady(2*time.Second, nil); err != nil {
		t.Fatal(err)
	}
	bucketName := fmt.Sprintf("t-%s", uuid.New())
	m := c.Buckets()
	if err := m.CreateBucket(gocb.CreateBucketSettings{
		BucketSettings: gocb.BucketSettings{
			Name:                 bucketName,
			FlushEnabled:         true,
			ReplicaIndexDisabled: true,
			RAMQuotaMB:           MinRamQuotaMB,
			NumReplicas:          0,
			BucketType:           gocb.CouchbaseBucketType,
		},
		ConflictResolutionType: gocb.ConflictResolutionTypeSequenceNumber,
	}, nil); err != nil {
		t.Fatal(err)
	}
	b := c.Bucket(bucketName)
	if err := b.WaitUntilReady(time.Second * 2, nil); err != nil {
		t.Fatal(err)
	}
	v := "v"
	res, err := b.DefaultCollection().Upsert("k", &v, nil)
	if err != nil {
		t.Fatal(err)
	}
	t.Log(res.Cas())

@1110 that looks like it should work, depending on your setup 2 seconds may not be long enough for the bucket connections to initialise as it also takes some time for the bucket to be fully setup on the cluster after creation. If I try with a pre-existing bucket on the c.Bucket call then it works so does increasing the timeout for the just created bucket.

I’m afraid it does not depend on time of WaitUntilReady timeout. I got"unambiguous timeout" error even if I increase timeout value up to 10 seс. But if I’m inserting small delay (100ms) before b := c.Bucket(bucketName) everything is going Ok.

That’s odd. You try enabling the logger if you haven’t already with gocb.SetLogger(gocb.VerboseStdioLogger()) or gocb.SetLogger(gocb.DefaultStdioLogger()) and see if that shows up any issues.

Logging does not give too much. One of two errors happens.
Failed to perform select bucket against server (document not found | {"status_code":1,"bucket":"t-...
Or
Failed to perform select bucket against server (authentication failure | {"status_code":36,"bucket":"t-...
It still looks like server in some point of process of bucket creation when the request arrives.
At first glance, I don’t recognize any mechanics in the memdclient.Bootstrap that checks if the bucket has just been created, and if so, it does i.g. some error handling and repeats ExecSelectBucket

@1110 from that it looks like the SelectBucket command (which is a part of connection initialisation) is failing to find the bucket likely due to what you say. If the SelectBucket fails then the connection should repeatedly attempt to reinitialise until it’s successful or it’s told to stop by the application closing the cluster object.

Then it’s really odd. Well, I can live with hardcoded time.Sleep since in my use case it is a test.