-
Notifications
You must be signed in to change notification settings - Fork 7
Add pubsub support to the Glide driver #44
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -83,15 +83,31 @@ public class ValkeyGlideClusterConnection extends ValkeyGlideConnection implemen | |
| private final ValkeyGlideClusterSetCommands clusterSetCommands; | ||
|
|
||
| public ValkeyGlideClusterConnection(ClusterGlideClientAdapter clusterAdapter) { | ||
| this(clusterAdapter, null, Duration.ofMillis(100)); | ||
| this(clusterAdapter, null, Duration.ofMillis(100), null); | ||
| } | ||
|
|
||
| public ValkeyGlideClusterConnection(ClusterGlideClientAdapter clusterAdapter, @Nullable ValkeyGlideConnectionFactory factory) { | ||
| this(clusterAdapter, factory, Duration.ofMillis(100)); | ||
| public ValkeyGlideClusterConnection(ClusterGlideClientAdapter clusterAdapter, | ||
| @Nullable ValkeyGlideConnectionFactory factory) { | ||
| this(clusterAdapter, factory, Duration.ofMillis(100), null); | ||
| } | ||
|
|
||
| public ValkeyGlideClusterConnection(ClusterGlideClientAdapter clusterAdapter, @Nullable ValkeyGlideConnectionFactory factory, Duration cacheTimeout) { | ||
| super(clusterAdapter, factory); | ||
| public ValkeyGlideClusterConnection(ClusterGlideClientAdapter clusterAdapter, | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. empty line
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just looks like it bc of github |
||
| @Nullable ValkeyGlideConnectionFactory factory, | ||
| @Nullable DelegatingPubSubListener pubSubListener) { | ||
| this(clusterAdapter, factory, Duration.ofMillis(100), pubSubListener); | ||
| } | ||
|
|
||
| public ValkeyGlideClusterConnection(ClusterGlideClientAdapter clusterAdapter, | ||
| @Nullable ValkeyGlideConnectionFactory factory, | ||
| Duration cacheTimeout) { | ||
| this(clusterAdapter, factory, cacheTimeout, null); | ||
| } | ||
|
|
||
| public ValkeyGlideClusterConnection(ClusterGlideClientAdapter clusterAdapter, | ||
| @Nullable ValkeyGlideConnectionFactory factory, | ||
| Duration cacheTimeout, | ||
| @Nullable DelegatingPubSubListener pubSubListener) { | ||
| super(clusterAdapter, factory, pubSubListener); | ||
| Assert.notNull(cacheTimeout, "CacheTimeout must not be null!"); | ||
|
|
||
| this.clusterAdapter = clusterAdapter; | ||
|
|
@@ -123,10 +139,6 @@ protected void cleanupConnectionState() { | |
| @SuppressWarnings("unchecked") | ||
| Callable<Void>[] actions = new Callable[] { | ||
| () -> nativeClient.customCommand(new String[]{"UNWATCH"}, SimpleMultiNodeRoute.ALL_NODES).get(), | ||
| // TODO: Uncomment when dynamic pubsub is implemented | ||
| // () -> nativeClient.customCommand(new String[]{"UNSUBSCRIBE"}, SimpleMultiNodeRoute.ALL_NODES).get(), | ||
| // () -> nativeClient.customCommand(new String[]{"PUNSUBSCRIBE"}, SimpleMultiNodeRoute.ALL_NODES).get(), | ||
| // () -> nativeClient.customCommand(new String[]{"SUNSUBSCRIBE"}, SimpleMultiNodeRoute.ALL_NODES).get() | ||
| }; | ||
|
|
||
| for (Callable<Void> action : actions) { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -41,17 +41,23 @@ | |
| // Imports for valkey-glide library | ||
| import glide.api.GlideClient; | ||
| import glide.api.GlideClusterClient; | ||
| import glide.api.models.GlideString; | ||
| import glide.api.models.configuration.AdvancedGlideClientConfiguration; | ||
| import glide.api.models.configuration.AdvancedGlideClusterClientConfiguration; | ||
| import glide.api.models.configuration.BackoffStrategy; | ||
| import glide.api.models.configuration.GlideClientConfiguration; | ||
| import glide.api.models.configuration.GlideClusterClientConfiguration; | ||
| import glide.api.models.configuration.NodeAddress; | ||
| import glide.api.models.configuration.ReadFrom; | ||
| import glide.api.models.configuration.StandaloneSubscriptionConfiguration; | ||
| import glide.api.models.configuration.ClusterSubscriptionConfiguration; | ||
|
|
||
| import java.util.Map; | ||
| import java.util.Set; | ||
| import java.util.LinkedList; | ||
| import java.util.Queue; | ||
| import java.util.concurrent.BlockingQueue; | ||
| import java.util.concurrent.ConcurrentHashMap; | ||
| import java.util.concurrent.LinkedBlockingQueue; | ||
|
|
||
| /** | ||
|
|
@@ -91,6 +97,23 @@ public class ValkeyGlideConnectionFactory | |
| private boolean earlyStartup = true; | ||
| private int phase = 0; | ||
|
|
||
| /** | ||
| * Maps native Glide clients ({@link GlideClient} or {@link GlideClusterClient}) to their | ||
| * associated {@link DelegatingPubSubListener}. | ||
| * | ||
| * <p>This mapping is necessary because Glide requires pub/sub callbacks to be configured | ||
| * at client creation time, before any subscriptions exist. When a client is created and | ||
| * added to the pool, we also create a {@link DelegatingPubSubListener} and register it | ||
| * as the client's pub/sub callback. The actual {@link MessageListener} is set on the | ||
| * {@link DelegatingPubSubListener} later when {@code subscribe()} is called. | ||
| * | ||
| * <p>When a connection is obtained from the pool, we look up the corresponding | ||
| * {@link DelegatingPubSubListener} for that client and pass it to the | ||
| * {@link ValkeyGlideConnection}, which can then configure it with the user's | ||
| * {@link MessageListener} during subscription. | ||
| */ | ||
| private final Map<Object, DelegatingPubSubListener> clientListenerMap = new ConcurrentHashMap<>(); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. please comment what is the Object and what for
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added |
||
|
|
||
| /** | ||
| * Constructs a new {@link ValkeyGlideConnectionFactory} instance with default settings. | ||
| */ | ||
|
|
@@ -235,8 +258,11 @@ public ValkeyConnection getConnection() { | |
| client = createGlideClient(); | ||
| } | ||
|
|
||
| // Get the listener associated with this client | ||
| DelegatingPubSubListener listener = clientListenerMap.get(client); | ||
|
|
||
| // Return a new connection wrapper around the pooled client | ||
| return new ValkeyGlideConnection(new StandaloneGlideClientAdapter(client), this); | ||
| return new ValkeyGlideConnection(new StandaloneGlideClientAdapter(client), this, listener); | ||
| } | ||
|
|
||
| @Override | ||
|
|
@@ -253,8 +279,11 @@ public ValkeyClusterConnection getClusterConnection() { | |
| client = createGlideClusterClient(); | ||
| } | ||
|
|
||
| // Get the listener associated with this client | ||
| DelegatingPubSubListener listener = clientListenerMap.get(client); | ||
|
|
||
| // Return a new connection wrapper around the pooled cluster client | ||
| return new ValkeyGlideClusterConnection(new ClusterGlideClientAdapter(client), this); | ||
| return new ValkeyGlideClusterConnection(new ClusterGlideClientAdapter(client), this, listener); | ||
| } | ||
|
|
||
| @Override | ||
|
|
@@ -378,10 +407,26 @@ private GlideClient createGlideClient() { | |
| if (reconnectStrategy != null) { | ||
| configBuilder.reconnectStrategy(reconnectStrategy); | ||
| } | ||
|
|
||
| // Pubsub listener | ||
| DelegatingPubSubListener clientListener = new DelegatingPubSubListener(); | ||
|
|
||
|
|
||
| // Configure pub/sub with callback for event-driven message delivery | ||
| var subConfigBuilder = StandaloneSubscriptionConfiguration.builder(); | ||
|
|
||
| // Set callback that delegates to our listener holder | ||
| subConfigBuilder.callback((msg, context) -> clientListener.onMessage(msg, context)); | ||
| configBuilder.subscriptionConfiguration(subConfigBuilder.build()); | ||
|
|
||
| // Build and create client | ||
| GlideClientConfiguration config = configBuilder.build(); | ||
| return GlideClient.createClient(config).get(); | ||
| GlideClient client = GlideClient.createClient(config).get(); | ||
|
|
||
| // Save the mapping of this client to its DelegatingListener | ||
| clientListenerMap.put(client, clientListener); | ||
|
|
||
| return client; | ||
| } catch (Exception e) { | ||
| throw new IllegalStateException("Failed to create GlideClient: " + e.getMessage(), e); | ||
| } | ||
|
|
@@ -477,10 +522,24 @@ private GlideClusterClient createGlideClusterClient() { | |
| configBuilder.reconnectStrategy(reconnectStrategy); | ||
| } | ||
|
|
||
|
|
||
| DelegatingPubSubListener clientListener = new DelegatingPubSubListener(); | ||
|
|
||
| // Configure pub/sub with callback for event-driven message delivery | ||
| var subConfigBuilder = ClusterSubscriptionConfiguration.builder(); | ||
|
|
||
| // Set callback that delegates to our listener holder | ||
| subConfigBuilder.callback((msg, context) -> clientListener.onMessage(msg, context)); | ||
| configBuilder.subscriptionConfiguration(subConfigBuilder.build()); | ||
|
|
||
|
|
||
| // Build and create cluster client | ||
| GlideClusterClientConfiguration config = configBuilder.build(); | ||
| return GlideClusterClient.createClient(config).get(); | ||
| GlideClusterClient client = GlideClusterClient.createClient(config).get(); | ||
|
|
||
| clientListenerMap.put(client, clientListener); | ||
|
|
||
| return client; | ||
| } catch (InterruptedException | ExecutionException e) { | ||
| throw new IllegalStateException("Failed to create GlideClusterClient: " + e.getMessage(), e); | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
empty line
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just appears this way on github, see + signs beside