Skip to content
This repository was archived by the owner on Mar 13, 2021. It is now read-only.

Commit 439f767

Browse files
committed
Work around cancel() after complete() wrong behavior in reactive-grpc
1 parent 3d925f1 commit 439f767

File tree

1 file changed

+49
-0
lines changed

1 file changed

+49
-0
lines changed

src/main/java/io/projectriff/invoker/server/GrpcServerAdapter.java

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
import io.projectriff.invoker.rpc.OutputFrame;
77
import io.projectriff.invoker.rpc.OutputSignal;
88
import io.projectriff.invoker.rpc.ReactorRiffGrpc;
9+
import org.reactivestreams.Publisher;
10+
import org.reactivestreams.Subscription;
911
import org.springframework.cloud.function.context.FunctionCatalog;
1012
import org.springframework.cloud.function.context.catalog.FunctionInspector;
1113
import org.springframework.cloud.function.context.catalog.FunctionTypeUtils;
@@ -14,14 +16,17 @@
1416
import org.springframework.messaging.support.GenericMessage;
1517
import org.springframework.messaging.support.MessageBuilder;
1618
import org.springframework.util.MimeType;
19+
import reactor.core.CoreSubscriber;
1720
import reactor.core.publisher.Flux;
1821
import reactor.core.publisher.GroupedFlux;
22+
import reactor.core.publisher.Operators;
1923
import reactor.core.publisher.Signal;
2024
import reactor.util.function.Tuple2;
2125
import reactor.util.function.Tuples;
2226

2327
import java.lang.reflect.Type;
2428
import java.util.Comparator;
29+
import java.util.concurrent.atomic.AtomicBoolean;
2530
import java.util.function.Function;
2631

2732
/**
@@ -111,6 +116,9 @@ private Function<Flux<Tuple2<Integer, Message<byte[]>>>, Flux<Tuple2<Integer, Me
111116
return
112117
// stick dummy messages in front to force the creation of each arg-index group
113118
flux -> flux.startWith(startTuples)
119+
// Work around bug in reactive-grpc which freaks out on cancels happening after complete when
120+
// it shouldn't. Those cancels are a consequence of FluxGroupBy.complete()
121+
.transform(ignoreCancelsAfterComplete())
114122
// group by arg index (ie de-mux)
115123
.groupBy(Tuple2::getT1, Tuple2::getT2)
116124
// chop the outer flux. We know there will ever be exactly that many groups
@@ -138,6 +146,47 @@ private Function<Flux<Tuple2<Integer, Message<byte[]>>>, Flux<Tuple2<Integer, Me
138146
;
139147
}
140148

149+
// Used to transform the publisher chain into one that doesn't forward cancel() calls once it has complete()d.
150+
private Function<? super Publisher<Tuple2<Integer, Message<byte[]>>>, ? extends Publisher<Tuple2<Integer, Message<byte[]>>>> ignoreCancelsAfterComplete() {
151+
return Operators.lift((f, actual) ->
152+
new CoreSubscriber<>() {
153+
AtomicBoolean completed = new AtomicBoolean();
154+
155+
@Override
156+
public void onSubscribe(Subscription s) {
157+
actual.onSubscribe(new Subscription() {
158+
@Override
159+
public void request(long n) {
160+
s.request(n);
161+
}
162+
163+
@Override
164+
public void cancel() {
165+
if (!completed.get()) {
166+
s.cancel();
167+
}
168+
}
169+
});
170+
}
171+
172+
@Override
173+
public void onNext(Tuple2<Integer, Message<byte[]>> objects) {
174+
actual.onNext(objects);
175+
}
176+
177+
@Override
178+
public void onError(Throwable t) {
179+
actual.onError(t);
180+
}
181+
182+
@Override
183+
public void onComplete() {
184+
completed.compareAndSet(false, true);
185+
actual.onComplete();
186+
}
187+
});
188+
}
189+
141190
private Flux<Message<byte[]>>[] promoteToArray(Object result) {
142191
if (result instanceof Tuple2) {
143192
Object[] objects = ((Tuple2) result).toArray();

0 commit comments

Comments
 (0)