EventStore / EventStoreDB-Client-Java

Official Asynchronous Java 8+ Client Library for EventStoreDB 20.6+
https://eventstore.com
Apache License 2.0
61 stars 19 forks source link

java.lang.IllegalStateException: call was cancelled #248

Closed Grisu118 closed 8 months ago

Grisu118 commented 8 months ago

Your change here: https://github.com/EventStore/EventStoreDB-Client-Java/commit/d547913e917139d956bcb8bfcb63c5f92c77e117#diff-2e76b08b20d1e7bd4e2f0376d0e3eb5d4a2e4caa3dd741aa33f672c39f51fff2R116

Results in the following exception if Subscription::stop is called

Nov 02, 2023 4:00:31 PM io.grpc.internal.SerializingExecutor run
SEVERE: Exception while executing runnable io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1StreamClosed@707b11e9
java.lang.IllegalStateException: call was cancelled
    at com.google.common.base.Preconditions.checkState(Preconditions.java:512)
    at io.grpc.internal.ClientCallImpl.halfCloseInternal(ClientCallImpl.java:510)
    at io.grpc.internal.ClientCallImpl.halfClose(ClientCallImpl.java:504)
    at io.grpc.PartialForwardingClientCall.halfClose(PartialForwardingClientCall.java:44)
    at io.grpc.ForwardingClientCall.halfClose(ForwardingClientCall.java:22)
    at io.grpc.ForwardingClientCall$SimpleForwardingClientCall.halfClose(ForwardingClientCall.java:44)
    at io.grpc.stub.ClientCalls$CallToStreamObserverAdapter.onCompleted(ClientCalls.java:379)
    at com.eventstore.dbclient.AbstractRegularSubscription$1.onError(AbstractRegularSubscription.java:116)
    at io.grpc.stub.ClientCalls$StreamObserverToCallListenerAdapter.onClose(ClientCalls.java:481)
    at io.grpc.internal.ClientCallImpl.closeObserver(ClientCallImpl.java:574)
    at io.grpc.internal.ClientCallImpl.access$300(ClientCallImpl.java:72)
    at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1StreamClosed.runInternal(ClientCallImpl.java:742)
    at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1StreamClosed.runInContext(ClientCallImpl.java:723)
    at io.grpc.internal.ContextRunnable.run(ContextRunnable.java:37)
    at io.grpc.internal.SerializingExecutor.run(SerializingExecutor.java:133)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
    at java.base/java.lang.Thread.run(Thread.java:840)

As far as I understand, the following happens

  1. Subscription::stop -> this._requestStream.cancel("user-initiated", null);
  2. This causes a call to the onError handler with grpc status cancelled
  3. Then you try to call _requestStream.onCompleted();, which seems to be not allowed on an already cancelled stream

Repoducer

 @Test
  void repro() throws ExecutionException, InterruptedException, TimeoutException {
    var settings = EventStoreDBConnectionString.parseOrThrow(this.container.getConnectionString());
    // Build client
    var client = EventStoreDBClient.create(settings);

    client.appendToStream("test", EventData.builderAsJson("TEST", "Hello World").build()).get(60, TimeUnit.SECONDS);

    var sub = client.subscribeToAll(new SubscriptionListener() {
      @Override
      public void onEvent(Subscription subscription, ResolvedEvent event) {
        System.out.println("onEvent" + event);
      }

      @Override
      public void onCancelled(Subscription subscription, Throwable exception) {
        System.out.println("onCancelled");
      }

      @Override
      public void onConfirmation(Subscription subscription) {
        System.out.println("onConfirmation");
      }
    }).get(60, TimeUnit.SECONDS);

    // Thread.sleep(5000);

    sub.stop();

  }
}
YoEight commented 8 months ago

Thanks @Grisu118 for reporting this, I'll get a patch out as soon as possible

YoEight commented 8 months ago

Will get a release ready tomorrow on Maven Central

YoEight commented 8 months ago

Version 5.1.1 is available on Maven Central.

Grisu118 commented 8 months ago

Thanks for the fast fix :+1: