EventStore / EventStoreDB-Client-Java

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

Improve InterruptedException handling in com.eventstore.dbclient.GrpcClient. #223

Closed jezovuk closed 1 year ago

jezovuk commented 1 year ago

Current implementation of com.eventstore.dbclient.GrpcClient.pushMsg(Msg) logs and swallows the InterruptedException. It seems more appropriate to propagate the exception instead (perhaps wrapped in RuntimeException or similar), since this is called on application/caller thread.

There might be other places (in GrpcClient or elsewhere) which could benefit from stricter interrupt handling. (I have checked GrpcClient code but do not have sufficient understanding of client lifecycle to detect any further problems).

YoEight commented 1 year ago

Hey @jezovuk ,

That exception will ever occur if the thread got interrupted while we are waiting for msg to be inserted in the queue. In other word, the user has to interrupt the thread they are running on themselves. I argue there is no value at propagating that exception upward for this reason specifically.

jezovuk commented 1 year ago

Technically, not only if interrupted while waiting, but also if interrupted before attempting the insert (before this.messages.put(msg) is called).

Regarding this: In other word, the user has to interrupt the thread they are running on themselves.

My scenario is as follows:

If com.eventstore.dbclient.GrpcClient.pushMsg(Msg) were to propagate the interrupt (re-throw InterruptedException), we could/would handle it in our task impl (run() method) and skip any further operations in that run, thus enabling quick and orderly executor (and thus ThreadPoolTaskScheduler and entire module) shutdown.

YoEight commented 1 year ago

Technically, not only if interrupted while waiting, but also if interrupted before attempting the insert (before this.messages.put(msg) is called).

The docs are pretty clear on this, it won't happen prior to that point. Also, comment out that put call and there is no InterruptedException to catch.

I do agree though that your scenario warrants propagating that exception. However, I don't see any way to achieve this without breaking the API, I don't think wrapping that exception into a RuntimeException to be satisfactory.

Unless you already have an implementation on your mind, I will need some time to rewrite that part of the code to support your use case.

jezovuk commented 1 year ago

The docs are pretty clear on this, it won't happen prior to that point. Also, comment out that put call and there is no InterruptedException to catch.

Perhaps I was not precise enough. When I said "if interrupted before attempting the insert", I was talking about Thread.interrput() being called (from another thread) on Thread object representing the trhead pushing the message before it invokes this.messages.put(msg) (or even before it invokes com.eventstore.dbclient.GrpcClient.pushMsg(Msg)). It is clear that actual InterruptedException can only be raised by pushMsg(...) here.

As for proposed solution, I have no problems with wrapping the InterruptedException in RuntimeException (or some more specific subclass of it), at least as a starting point, until API changes required to propagate InterruptedException directly can be thought through and implemented. It is certainly better for me than current behavior which can lead to indefinite blocking on CompletableFuture.join().