16
16
package org .springframework .data .redis .connection .lettuce ;
17
17
18
18
import io .lettuce .core .pubsub .StatefulRedisPubSubConnection ;
19
+ import io .lettuce .core .pubsub .api .async .RedisPubSubAsyncCommands ;
19
20
import io .lettuce .core .pubsub .api .sync .RedisPubSubCommands ;
20
21
22
+ import java .util .ArrayList ;
23
+ import java .util .List ;
24
+ import java .util .concurrent .CompletableFuture ;
25
+
21
26
import org .springframework .data .redis .connection .MessageListener ;
22
27
import org .springframework .data .redis .connection .util .AbstractSubscription ;
23
28
@@ -37,6 +42,7 @@ public class LettuceSubscription extends AbstractSubscription {
37
42
private final LettuceMessageListener listener ;
38
43
private final LettuceConnectionProvider connectionProvider ;
39
44
private final RedisPubSubCommands <byte [], byte []> pubsub ;
45
+ private final RedisPubSubAsyncCommands <byte [], byte []> pubSubAsync ;
40
46
41
47
/**
42
48
* Creates a new {@link LettuceSubscription} given {@link MessageListener}, {@link StatefulRedisPubSubConnection}, and
@@ -55,6 +61,7 @@ protected LettuceSubscription(MessageListener listener,
55
61
this .listener = new LettuceMessageListener (listener );
56
62
this .connectionProvider = connectionProvider ;
57
63
this .pubsub = connection .sync ();
64
+ this .pubSubAsync = connection .async ();
58
65
59
66
this .connection .addListener (this .listener );
60
67
}
@@ -70,15 +77,29 @@ protected StatefulRedisPubSubConnection<byte[], byte[]> getNativeConnection() {
70
77
@ Override
71
78
protected void doClose () {
72
79
80
+ List <CompletableFuture <?>> futures = new ArrayList <>();
81
+
73
82
if (!getChannels ().isEmpty ()) {
74
- doUnsubscribe ( true );
83
+ futures . add ( pubSubAsync . unsubscribe (). toCompletableFuture () );
75
84
}
76
85
77
86
if (!getPatterns ().isEmpty ()) {
78
- doPUnsubscribe (true );
87
+ futures .add (pubSubAsync .punsubscribe ().toCompletableFuture ());
88
+ }
89
+
90
+ if (!futures .isEmpty ()) {
91
+
92
+ // this is to ensure completion of the futures and result processing. Since we're unsubscribing first, we expect
93
+ // that we receive pub/sub confirmations before the PING response.
94
+ futures .add (pubSubAsync .ping ().toCompletableFuture ());
95
+
96
+ CompletableFuture .allOf (futures .toArray (new CompletableFuture [0 ])).whenComplete ((v , t ) -> {
97
+ connection .removeListener (listener );
98
+ });
99
+ } else {
100
+ connection .removeListener (listener );
79
101
}
80
102
81
- connection .removeListener (this .listener );
82
103
connectionProvider .release (connection );
83
104
}
84
105
0 commit comments