Skip to content
This repository was archived by the owner on Mar 9, 2025. It is now read-only.

Commit e81ae86

Browse files
resolve issue #77
* handle vshard error the same way as lua vshard router.
1 parent b063b2b commit e81ae86

File tree

2 files changed

+47
-11
lines changed

2 files changed

+47
-11
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ BUG FIXES:
66
CHANGES:
77
* Add comment why and how we handle "NON_MASTER" vshard error.
88
* Don't support 'type Error struct' anymore.
9+
* Handle vshard error the same way as lua vshard router (resolve issue #77).
910

1011
FEATURES:
1112

api.go

Lines changed: 46 additions & 11 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 {
@@ -171,17 +172,42 @@ func (r *Router) RouterCallImpl(ctx context.Context,
171172
case VShardErrNameWrongBucket, VShardErrNameBucketIsLocked:
172173
r.BucketReset(bucketID)
173174

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.
178-
r.metrics().RetryOnCall("bucket_migrate")
179-
180-
r.log().Debugf(ctx, "retrying fnc '%s' cause got vshard error: %v", fnc, &vshardError)
181-
182-
// this vshardError will be returned to a caller in case of timeout
183-
err = &vshardError
184-
continue
175+
if vshardError.Destination == "" {
176+
break // leads to retry
177+
}
178+
179+
destinationUUID, err := uuid.Parse(vshardError.Destination)
180+
if err != nil {
181+
return nil, nil, fmt.Errorf("protocol violation %s: malformed destination %w: %w",
182+
vshardStorageClientCall, vshardError, err)
183+
}
184+
185+
var loggedOnce bool
186+
for {
187+
idToReplicasetRef := r.getIDToReplicaset()
188+
if _, ok := idToReplicasetRef[destinationUUID]; ok {
189+
_, err := r.BucketSet(bucketID, destinationUUID)
190+
if err == nil {
191+
break // loop
192+
}
193+
r.log().Warnf(ctx, "Failed set bucket %d to %v (possible race): %v", bucketID, destinationUUID, err)
194+
}
195+
196+
if !loggedOnce {
197+
r.log().Warnf(ctx, "Replicaset '%v' was not found, but received from storage as destination - please "+
198+
"update configuration", destinationUUID)
199+
loggedOnce = true
200+
}
201+
202+
const defaultPoolingPause = 50 * time.Millisecond
203+
time.Sleep(defaultPoolingPause)
204+
205+
if time.Since(timeStart) > timeout {
206+
return nil, nil, &vshardError
207+
}
208+
}
209+
210+
// leads to retry
185211
case VShardErrNameTransferIsInProgress:
186212
// Since lua vshard router doesn't retry here, we don't retry too.
187213
// There is a comment why lua vshard router doesn't retry:
@@ -197,6 +223,15 @@ func (r *Router) RouterCallImpl(ctx context.Context,
197223
default:
198224
return nil, nil, &vshardError
199225
}
226+
227+
// retry for VShardErrNameWrongBucket, VShardErrNameBucketIsLocked
228+
229+
r.metrics().RetryOnCall("bucket_migrate")
230+
231+
r.log().Debugf(ctx, "retrying fnc '%s' cause got vshard error: %v", fnc, &vshardError)
232+
233+
// this vshardError will be returned to a caller in case of timeout
234+
err = &vshardError
200235
}
201236

202237
var isVShardRespOk bool

0 commit comments

Comments
 (0)