Skip to content

Commit e025d0b

Browse files
resolve issue #77 (#107)
1 parent 097ac24 commit e025d0b

File tree

2 files changed

+38
-4
lines changed

2 files changed

+38
-4
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ CHANGES:
88
* Don't support 'type Error struct' anymore.
99
* Linter: don't capitalize error strings and capitalize log.
1010
* Fix misspellings.
11+
* Handle vshard error the same way as lua vshard router (resolve issue #77).
1112

1213
FEATURES:
1314

api.go

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ type StorageCallVShardError struct {
5252
MasterUUID string `msgpack:"master" mapstructure:"master"`
5353
ReplicasetUUID string `msgpack:"replicaset" mapstructure:"replicaset"`
5454
ReplicaUUID string `msgpack:"replica" mapstructure:"replica"`
55+
Destination string `msgpack:"destination" mapstructure:"destination"`
5556
}
5657

5758
func (s StorageCallVShardError) Error() string {
@@ -169,12 +170,44 @@ func (r *Router) RouterCallImpl(ctx context.Context,
169170

170171
switch vshardError.Name {
171172
case VShardErrNameWrongBucket, VShardErrNameBucketIsLocked:
173+
// We reproduce here behavior in https://github.com/tarantool/vshard/blob/b6fdbe950a2e4557f05b83bd8b846b126ec3724e/vshard/router/init.lua#L663
172174
r.BucketReset(bucketID)
173175

174-
// TODO we should inspect here err.destination like lua vshard router does,
175-
// but we don't support vshard error fully yet:
176-
// https://github.com/KaymeKaydex/go-vshard-router/issues/94
177-
// So we just retry here as a temporary solution.
176+
if vshardError.Destination != "" {
177+
destinationUUID, err := uuid.Parse(vshardError.Destination)
178+
if err != nil {
179+
return nil, nil, fmt.Errorf("protocol violation %s: malformed destination %w: %w",
180+
vshardStorageClientCall, vshardError, err)
181+
}
182+
183+
var loggedOnce bool
184+
for {
185+
idToReplicasetRef := r.getIDToReplicaset()
186+
if _, ok := idToReplicasetRef[destinationUUID]; ok {
187+
_, err := r.BucketSet(bucketID, destinationUUID)
188+
if err == nil {
189+
break // breaks loop
190+
}
191+
r.log().Warnf(ctx, "Failed set bucket %d to %v (possible race): %v", bucketID, destinationUUID, err)
192+
}
193+
194+
if !loggedOnce {
195+
r.log().Warnf(ctx, "Replicaset '%v' was not found, but received from storage as destination - please "+
196+
"update configuration", destinationUUID)
197+
loggedOnce = true
198+
}
199+
200+
const defaultPoolingPause = 50 * time.Millisecond
201+
time.Sleep(defaultPoolingPause)
202+
203+
if time.Since(timeStart) > timeout {
204+
return nil, nil, &vshardError
205+
}
206+
}
207+
}
208+
209+
// retry for VShardErrNameWrongBucket, VShardErrNameBucketIsLocked
210+
178211
r.metrics().RetryOnCall("bucket_migrate")
179212

180213
r.log().Debugf(ctx, "Retrying fnc '%s' cause got vshard error: %v", fnc, &vshardError)

0 commit comments

Comments
 (0)