Skip to content

Commit 6a26595

Browse files
committed
Split ServerRoleSingleResilient in Active/Passive
1 parent 6282f83 commit 6a26595

File tree

5 files changed

+68
-14
lines changed

5 files changed

+68
-14
lines changed

client_cluster_impl.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ func (c *client) Cluster(ctx context.Context) (Cluster, error) {
3434
if err != nil {
3535
return nil, WithStack(err)
3636
}
37-
if role == ServerRoleSingle || role == ServerRoleSingleResilient {
37+
if role == ServerRoleSingle || role == ServerRoleSingleActive || role == ServerRoleSinglePassive {
3838
// Standalone server, this is wrong
3939
return nil, WithStack(newArangoError(412, 0, "Cluster expected, found SINGLE server"))
4040
}

client_server_info.go

+4-2
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,10 @@ type ServerRole string
4242
const (
4343
// ServerRoleSingle indicates that the server is a single-server instance
4444
ServerRoleSingle ServerRole = "Single"
45-
// ServerRoleSingleResilient indicates that the server is a single-server instance of a resilient pair
46-
ServerRoleSingleResilient ServerRole = "SingleResilient"
45+
// ServerRoleSingleActive indicates that the server is a the leader of a single-server resilient pair
46+
ServerRoleSingleActive ServerRole = "SingleActive"
47+
// ServerRoleSinglePassive indicates that the server is a a follower of a single-server resilient pair
48+
ServerRoleSinglePassive ServerRole = "SinglePassive"
4749
// ServerRoleDBServer indicates that the server is a dbserver within a cluster
4850
ServerRoleDBServer ServerRole = "DBServer"
4951
// ServerRoleCoordinator indicates that the server is a coordinator within a cluster

client_server_info_impl.go

+36-10
Original file line numberDiff line numberDiff line change
@@ -54,26 +54,31 @@ type roleResponse struct {
5454
Mode string `json:"mode,omitempty"`
5555
}
5656

57-
// AsServerRole converts the response into a ServerRole
58-
func (r roleResponse) AsServerRole() ServerRole {
57+
// asServerRole converts the response into a ServerRole
58+
func (r roleResponse) asServerRole(ctx context.Context, c *client) (ServerRole, error) {
5959
switch r.Role {
6060
case "SINGLE":
6161
switch r.Mode {
6262
case "resilient":
63-
return ServerRoleSingleResilient
63+
if err := c.echo(ctx); IsNoLeader(err) {
64+
return ServerRoleSinglePassive, nil
65+
} else if err != nil {
66+
return ServerRoleUndefined, WithStack(err)
67+
}
68+
return ServerRoleSingleActive, nil
6469
default:
65-
return ServerRoleSingle
70+
return ServerRoleSingle, nil
6671
}
6772
case "PRIMARY":
68-
return ServerRoleDBServer
73+
return ServerRoleDBServer, nil
6974
case "COORDINATOR":
70-
return ServerRoleCoordinator
75+
return ServerRoleCoordinator, nil
7176
case "AGENT":
72-
return ServerRoleAgent
77+
return ServerRoleAgent, nil
7378
case "UNDEFINED":
74-
return ServerRoleUndefined
79+
return ServerRoleUndefined, nil
7580
default:
76-
return ServerRoleUndefined
81+
return ServerRoleUndefined, nil
7782
}
7883
}
7984

@@ -95,5 +100,26 @@ func (c *client) ServerRole(ctx context.Context) (ServerRole, error) {
95100
if err := resp.ParseBody("", &data); err != nil {
96101
return ServerRoleUndefined, WithStack(err)
97102
}
98-
return data.AsServerRole(), nil
103+
role, err := data.asServerRole(ctx, c)
104+
if err != nil {
105+
return ServerRoleUndefined, WithStack(err)
106+
}
107+
return role, nil
108+
}
109+
110+
// clusterEndpoints returns the endpoints of a cluster.
111+
func (c *client) echo(ctx context.Context) error {
112+
req, err := c.conn.NewRequest("GET", "_admin/echo")
113+
if err != nil {
114+
return WithStack(err)
115+
}
116+
applyContextSettings(ctx, req)
117+
resp, err := c.conn.Do(ctx, req)
118+
if err != nil {
119+
return WithStack(err)
120+
}
121+
if err := resp.CheckStatus(200); err != nil {
122+
return WithStack(err)
123+
}
124+
return nil
99125
}

cluster/cluster.go

+12-1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ import (
3535
driver "github.com/arangodb/go-driver"
3636
)
3737

38+
const (
39+
keyFollowLeaderRedirect driver.ContextKey = "arangodb-followLeaderRedirect"
40+
)
41+
3842
// ConnectionConfig provides all configuration options for a cluster connection.
3943
type ConnectionConfig struct {
4044
// DefaultTimeout is the timeout used by requests that have no timeout set in the given context.
@@ -102,8 +106,15 @@ func (c *clusterConnection) NewRequest(method, path string) (driver.Request, err
102106

103107
// Do performs a given request, returning its response.
104108
func (c *clusterConnection) Do(ctx context.Context, req driver.Request) (driver.Response, error) {
109+
followLeaderRedirect := true
105110
if ctx == nil {
106111
ctx = context.Background()
112+
} else {
113+
if v := ctx.Value(keyFollowLeaderRedirect); v != nil {
114+
if on, ok := v.(bool); ok {
115+
followLeaderRedirect = on
116+
}
117+
}
107118
}
108119
// Timeout management.
109120
// We take the given timeout and divide it in 3 so we allow for other servers
@@ -156,7 +167,7 @@ func (c *clusterConnection) Do(ctx context.Context, req driver.Request) (driver.
156167
}
157168

158169
}
159-
if !isNoLeaderResponse {
170+
if !isNoLeaderResponse || !followLeaderRedirect {
160171
if err == nil {
161172
// We're done
162173
return resp, nil

context.go

+15
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ const (
5353
keyIgnoreRevs ContextKey = "arangodb-ignoreRevs"
5454
keyEnforceReplicationFactor ContextKey = "arangodb-enforceReplicationFactor"
5555
keyConfigured ContextKey = "arangodb-configured"
56+
keyFollowLeaderRedirect ContextKey = "arangodb-followLeaderRedirect"
5657
)
5758

5859
// WithRevision is used to configure a context to make document
@@ -192,6 +193,13 @@ func WithConfigured(parent context.Context, value ...bool) context.Context {
192193
return context.WithValue(contextOrBackground(parent), keyConfigured, v)
193194
}
194195

196+
// WithFollowLeaderRedirect is used to configure a context to return turn on/off
197+
// following redirection responses from the server when the request is answered by a follower.
198+
// Default behavior is "on".
199+
func WithFollowLeaderRedirect(parent context.Context, value bool) context.Context {
200+
return context.WithValue(contextOrBackground(parent), keyFollowLeaderRedirect, value)
201+
}
202+
195203
type contextSettings struct {
196204
Silent bool
197205
WaitForSync bool
@@ -205,6 +213,7 @@ type contextSettings struct {
205213
IgnoreRevs *bool
206214
EnforceReplicationFactor *bool
207215
Configured *bool
216+
FollowLeaderRedirect *bool
208217
}
209218

210219
// applyContextSettings returns the settings configured in the context in the given request.
@@ -312,6 +321,12 @@ func applyContextSettings(ctx context.Context, req Request) contextSettings {
312321
result.Configured = &configured
313322
}
314323
}
324+
// FollowLeaderRedirect
325+
if v := ctx.Value(keyFollowLeaderRedirect); v != nil {
326+
if followLeaderRedirect, ok := v.(bool); ok {
327+
result.FollowLeaderRedirect = &followLeaderRedirect
328+
}
329+
}
315330
return result
316331
}
317332

0 commit comments

Comments
 (0)