7
7
//
8
8
import NIOCore
9
9
10
- /// Represents a `MOVED` redirection error from a Valkey cluster node.
10
+ /// Represents a redirection error from a Valkey cluster node.
11
11
///
12
12
/// When a client sends a command to a Valkey cluster node that doesn't own
13
13
/// the hash slot for the specified key, the node responds with a `MOVED` error
14
14
/// containing information about which node actually owns that slot.
15
15
///
16
+ /// When a client sends a command to a Valkey cluster node for a hash slot that
17
+ /// is currently migrating for a key that does not exist the node responds
18
+ /// with a `ASK` error containing information about which node is importing
19
+ /// that hash slot
20
+ ///
16
21
/// This error provides the necessary information for clients to redirect their
17
22
/// request to the correct node in the cluster.
18
23
@usableFromInline
19
- package struct ValkeyMovedError : Hashable , Sendable {
24
+ package struct ValkeyClusterRedirectionError : Hashable , Sendable {
25
+ @usableFromInline
26
+ package enum Redirection : Sendable {
27
+ case move
28
+ case ask
29
+ }
30
+
31
+ /// Request type
32
+ @usableFromInline
33
+ package var redirection : Redirection
34
+
20
35
/// The hash slot number that triggered the redirection.
21
36
package var slot : HashSlot
22
37
@@ -26,7 +41,8 @@ package struct ValkeyMovedError: Hashable, Sendable {
26
41
/// The port number of the node that owns the requested hash slot.
27
42
package var port : Int
28
43
29
- package init ( slot: HashSlot , endpoint: String , port: Int ) {
44
+ package init ( request: Redirection , slot: HashSlot , endpoint: String , port: Int ) {
45
+ self . redirection = request
30
46
self . slot = slot
31
47
self . endpoint = endpoint
32
48
self . port = port
@@ -38,25 +54,33 @@ package struct ValkeyMovedError: Hashable, Sendable {
38
54
}
39
55
}
40
56
41
- extension ValkeyMovedError {
57
+ extension ValkeyClusterRedirectionError {
42
58
static let movedPrefix = " MOVED "
59
+ static let askPrefix = " ASK "
43
60
44
- /// Attempts to parse a Valkey MOVED error from a String.
61
+ /// Attempts to parse a Valkey MOVED/ASK error from a String.
45
62
///
46
63
/// This method extracts the hash slot, endpoint, and port information from the string
47
- /// if it represents a Valkey MOVED error. MOVED errors are returned by Valkey cluster
48
- /// nodes when a client attempts to access a key that belongs to a different node.
64
+ /// if it represents a Valkey MOVED/ASK error. Redirection errors are returned by Valkey
65
+ /// cluster nodes when a client attempts to access a key that belongs to a different node
66
+ /// or the hashslot is currently migrating.
49
67
///
50
68
/// The error format is expected to be: `"MOVED <slot> <endpoint>:<port>"`
51
69
///
52
- /// - Returns: A `ValkeyMovedError ` if the token represents a valid MOVED error, or `nil` otherwise.
70
+ /// - Returns: A `ValkeyClusterRedirectionError ` if the token represents a valid MOVED/ASK error, or `nil` otherwise.
53
71
@usableFromInline
54
72
init ? ( _ errorMessage: String ) {
55
- guard errorMessage. hasPrefix ( Self . movedPrefix) else {
73
+ let msg : String . SubSequence
74
+ let request : Redirection
75
+ if errorMessage. hasPrefix ( Self . movedPrefix) {
76
+ msg = errorMessage. dropFirst ( Self . movedPrefix. count)
77
+ request = . move
78
+ } else if errorMessage. hasPrefix ( Self . askPrefix) {
79
+ msg = errorMessage. dropFirst ( Self . askPrefix. count)
80
+ request = . ask
81
+ } else {
56
82
return nil
57
83
}
58
-
59
- let msg = errorMessage. dropFirst ( Self . movedPrefix. count)
60
84
guard let spaceAfterSlotIndex = msg. firstIndex ( where: { $0 == " " } ) else {
61
85
return nil
62
86
}
@@ -79,6 +103,6 @@ extension ValkeyMovedError {
79
103
return nil
80
104
}
81
105
82
- self = ValkeyMovedError ( slot: slot, endpoint: Swift . String ( endpoint) , port: port)
106
+ self = ValkeyClusterRedirectionError ( request : request , slot: slot, endpoint: Swift . String ( endpoint) , port: port)
83
107
}
84
108
}
0 commit comments