Skip to content

Commit bd408cf

Browse files
ggivotishun
andauthored
[Hitless Upgrades] Zero-server-side configuration with client-side opt-in (redis#3380)
* Support for Client-side opt-in A client can tell the server if it wants to receive maintenance push notifications via the following command: CLIENT MAINT_NOTIFICATIONS <ON | OFF> [parameter value parameter value ...] * update maintenance events to latest format - MIGRATING <seq_number> <time> <shard_id-s>: A shard migration is going to start within <time> seconds. - MIGRATED <seq_number> <shard_id-s>: A shard migration ended. - FAILING_OVER <seq_number> <time> <shard_id-s>: A shard failover of a healthy shard started. - FAILED_OVER <seq_number> <shard_id-s>: A shard failover of a healthy shard ended. - MOVING <seq_number> <time> <endpoint>: A specific endpoint is going to move to another node within <time> seconds * clean up * Update FAILED_OVER & MIGRATED to include additional time field * update is private reserver check & add unit tests update is private reserver check * add unit tests for handshake with enabled maintenance events * add missing copyrights/docs * format * address review comments * Revert address after rebind operation expires * Update event's validation spec - MIGRATING <seq_number> <time> <shard_id-s>: A shard migration is going to start within <time> seconds. - MIGRATED <seq_number> <shard_id-s>: A shard migration ended. - FAILING_OVER <seq_number> <time> <shard_id-s>: A shard failover of a healthy shard started. - FAILED_OVER <seq_number> <shard_id-s>: A shard failover of a healthy shard ended. - MOVING <seq_number> <time> <endpoint>: A specific endpoint is going to move to another node within <time> seconds * rebase * format after rebase * Apply suggestions from code review Co-authored-by: Tihomir Krasimirov Mateev <tihomir.mateev@redis.com> * javadoc updated * Update src/main/java/io/lettuce/core/internal/NetUtils.java Co-authored-by: Tihomir Krasimirov Mateev <tihomir.mateev@redis.com> --------- Co-authored-by: Tihomir Krasimirov Mateev <tihomir.mateev@redis.com>
1 parent f35a488 commit bd408cf

24 files changed

+1272
-181
lines changed

src/main/java/io/lettuce/core/AbstractRedisClient.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
package io.lettuce.core;
2121

2222
import java.io.Closeable;
23+
import java.net.InetAddress;
24+
import java.net.InetSocketAddress;
2325
import java.net.SocketAddress;
2426
import java.time.Duration;
2527
import java.util.ArrayList;
@@ -34,6 +36,7 @@
3436
import java.util.concurrent.atomic.AtomicBoolean;
3537
import java.util.concurrent.atomic.AtomicInteger;
3638

39+
import io.lettuce.core.MaintenanceEventsOptions.AddressTypeSource;
3740
import reactor.core.publisher.Mono;
3841
import io.lettuce.core.event.command.CommandListener;
3942
import io.lettuce.core.event.connection.ConnectEvent;
@@ -629,8 +632,16 @@ private CompletableFuture<Void> closeClientResources(long quietPeriod, long time
629632
}
630633

631634
protected RedisHandshake createHandshake(ConnectionState state) {
635+
AddressTypeSource source = null;
636+
if (clientOptions.getMaintenanceEventsOptions().supportsMaintenanceEvents()) {
637+
LettuceAssert.notNull(clientOptions.getMaintenanceEventsOptions().getAddressTypeSource(),
638+
"Address type source must not be null");
639+
640+
source = clientOptions.getMaintenanceEventsOptions().getAddressTypeSource();
641+
}
642+
632643
return new RedisHandshake(clientOptions.getConfiguredProtocolVersion(), clientOptions.isPingBeforeActivateConnection(),
633-
state);
644+
state, source);
634645
}
635646

636647
}

src/main/java/io/lettuce/core/ClientOptions.java

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public class ClientOptions implements Serializable {
5252

5353
public static final boolean DEFAULT_AUTO_RECONNECT = true;
5454

55-
public static final boolean DEFAULT_SUPPORT_MAINTENANCE_EVENTS = false;
55+
public static final MaintenanceEventsOptions DEFAULT_MAINTENANCE_EVENTS_OPTIONS = MaintenanceEventsOptions.disabled();
5656

5757
public static final Predicate<RedisCommand<?, ?, ?>> DEFAULT_REPLAY_FILTER = (cmd) -> false;
5858

@@ -98,7 +98,7 @@ public class ClientOptions implements Serializable {
9898

9999
private final boolean autoReconnect;
100100

101-
private final boolean supportMaintenanceEvents;
101+
private final MaintenanceEventsOptions maintenanceEventsOptions;
102102

103103
private final Predicate<RedisCommand<?, ?, ?>> replayFilter;
104104

@@ -136,7 +136,7 @@ public class ClientOptions implements Serializable {
136136

137137
protected ClientOptions(Builder builder) {
138138
this.autoReconnect = builder.autoReconnect;
139-
this.supportMaintenanceEvents = builder.supportMaintenanceEvents;
139+
this.maintenanceEventsOptions = builder.maintenanceEventsOptions;
140140
this.replayFilter = builder.replayFilter;
141141
this.cancelCommandsOnReconnectFailure = builder.cancelCommandsOnReconnectFailure;
142142
this.decodeBufferPolicy = builder.decodeBufferPolicy;
@@ -158,7 +158,7 @@ protected ClientOptions(Builder builder) {
158158

159159
protected ClientOptions(ClientOptions original) {
160160
this.autoReconnect = original.isAutoReconnect();
161-
this.supportMaintenanceEvents = original.supportsMaintenanceEvents();
161+
this.maintenanceEventsOptions = original.getMaintenanceEventsOptions();
162162
this.replayFilter = original.getReplayFilter();
163163
this.cancelCommandsOnReconnectFailure = original.isCancelCommandsOnReconnectFailure();
164164
this.decodeBufferPolicy = original.getDecodeBufferPolicy();
@@ -213,7 +213,7 @@ public static class Builder {
213213

214214
private boolean autoReconnect = DEFAULT_AUTO_RECONNECT;
215215

216-
private boolean supportMaintenanceEvents = DEFAULT_SUPPORT_MAINTENANCE_EVENTS;
216+
private MaintenanceEventsOptions maintenanceEventsOptions = DEFAULT_MAINTENANCE_EVENTS_OPTIONS;
217217

218218
private Predicate<RedisCommand<?, ?, ?>> replayFilter = DEFAULT_REPLAY_FILTER;
219219

@@ -268,14 +268,14 @@ public Builder autoReconnect(boolean autoReconnect) {
268268
* Configure whether the driver should listen for server events that notify on current maintenance activities. When
269269
* enabled, this option will help with the connection handover and reduce the number of failed commands. This feature
270270
* requires the server to support maintenance events. Defaults to {@code false}. See
271-
* {@link #DEFAULT_SUPPORT_MAINTENANCE_EVENTS}.
271+
* {@link #DEFAULT_MAINTENANCE_EVENTS_OPTIONS}.
272272
*
273-
* @param supportEvents true/false
273+
* @param maintenanceEventsOptions true/false
274274
* @return {@code this}
275275
* @since 7.0
276276
*/
277-
public Builder supportMaintenanceEvents(boolean supportEvents) {
278-
this.supportMaintenanceEvents = supportEvents;
277+
public Builder supportMaintenanceEvents(MaintenanceEventsOptions maintenanceEventsOptions) {
278+
this.maintenanceEventsOptions = maintenanceEventsOptions;
279279
return this;
280280
}
281281

@@ -574,7 +574,7 @@ public ClientOptions build() {
574574
public ClientOptions.Builder mutate() {
575575
Builder builder = new Builder();
576576

577-
builder.autoReconnect(isAutoReconnect()).supportMaintenanceEvents(supportsMaintenanceEvents())
577+
builder.autoReconnect(isAutoReconnect()).supportMaintenanceEvents(getMaintenanceEventsOptions())
578578
.cancelCommandsOnReconnectFailure(isCancelCommandsOnReconnectFailure()).replayFilter(getReplayFilter())
579579
.decodeBufferPolicy(getDecodeBufferPolicy()).disconnectedBehavior(getDisconnectedBehavior())
580580
.reauthenticateBehavior(getReauthenticateBehaviour()).readOnlyCommands(getReadOnlyCommands())
@@ -601,15 +601,15 @@ public boolean isAutoReconnect() {
601601
}
602602

603603
/**
604-
* Returns whether the client supports maintenance events.
604+
* Returns the {@link MaintenanceEventsOptions} to listen for server events that notify on current maintenance activities.
605605
*
606-
* @return {@code true} if maintenance events are supported.
606+
* @return {@link MaintenanceEventsOptions}
607607
* @since 7.0
608-
* @see #DEFAULT_SUPPORT_MAINTENANCE_EVENTS
609-
* @see #supportsMaintenanceEvents()
608+
* @see #DEFAULT_MAINTENANCE_EVENTS_OPTIONS
609+
* @see #getMaintenanceEventsOptions()
610610
*/
611-
public boolean supportsMaintenanceEvents() {
612-
return supportMaintenanceEvents;
611+
public MaintenanceEventsOptions getMaintenanceEventsOptions() {
612+
return maintenanceEventsOptions;
613613
}
614614

615615
/**

src/main/java/io/lettuce/core/ConnectionBuilder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ protected ConnectionWatchdog createConnectionWatchdog() {
155155
LettuceAssert.assertState(socketAddressSupplier != null, "SocketAddressSupplier must be set for autoReconnect=true");
156156

157157
ConnectionWatchdog watchdog;
158-
if (clientOptions.supportsMaintenanceEvents()) {
158+
if (clientOptions.getMaintenanceEventsOptions().supportsMaintenanceEvents()) {
159159
watchdog = new MaintenanceAwareConnectionWatchdog(clientResources.reconnectDelay(), clientOptions, bootstrap,
160160
clientResources.timer(), clientResources.eventExecutorGroup(), socketAddressSupplier, reconnectionListener,
161161
connection, clientResources.eventBus(), endpoint);

src/main/java/io/lettuce/core/ConnectionMetadata.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ class ConnectionMetadata {
1111

1212
private volatile String libraryVersion;
1313

14+
private volatile boolean sslEnabled;
15+
1416
public ConnectionMetadata() {
1517
}
1618

@@ -23,13 +25,15 @@ public void apply(RedisURI redisURI) {
2325
setClientName(redisURI.getClientName());
2426
setLibraryName(redisURI.getLibraryName());
2527
setLibraryVersion(redisURI.getLibraryVersion());
28+
setSslEnabled(redisURI.isSsl());
2629
}
2730

2831
public void apply(ConnectionMetadata metadata) {
2932

3033
setClientName(metadata.getClientName());
3134
setLibraryName(metadata.getLibraryName());
3235
setLibraryVersion(metadata.getLibraryVersion());
36+
setSslEnabled(metadata.isSslEnabled());
3337
}
3438

3539
protected void setClientName(String clientName) {
@@ -56,4 +60,12 @@ String getLibraryVersion() {
5660
return libraryVersion;
5761
}
5862

63+
boolean isSslEnabled() {
64+
return sslEnabled;
65+
}
66+
67+
void setSslEnabled(boolean sslEnabled) {
68+
this.sslEnabled = sslEnabled;
69+
}
70+
5971
}

0 commit comments

Comments
 (0)