IGNITE-22101 Fix performance drop for thin client cache operations - Fixes #11328.

Signed-off-by: Aleksey Plekhanov <plehanov.alex@gmail.com>
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/ClientRequestHandler.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/ClientRequestHandler.java
index ecbf956..56b6636 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/ClientRequestHandler.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/ClientRequestHandler.java
@@ -20,6 +20,7 @@
 import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.IgniteIllegalStateException;
 import org.apache.ignite.IgniteLogger;
+import org.apache.ignite.internal.IgniteFutureTimeoutCheckedException;
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.binary.BinaryWriterExImpl;
 import org.apache.ignite.internal.processors.cache.query.IgniteQueryErrorCode;
@@ -45,6 +46,9 @@
  * Thin client request handler.
  */
 public class ClientRequestHandler implements ClientListenerRequestHandler {
+    /** Timeout to wait for async requests completion, to handle them as regular sync requests. */
+    private static final long ASYNC_REQUEST_WAIT_TIMEOUT_MILLIS = 10L;
+
     /** Client context. */
     private final ClientConnectionContext ctx;
 
@@ -118,17 +122,17 @@
         if (req0.isAsync(ctx)) {
             IgniteInternalFuture<ClientResponse> fut = req0.processAsync(ctx);
 
-            if (fut.isDone()) {
-                try {
-                    // Some async operations can be already finished after processAsync. Shortcut for this case.
-                    return fut.get();
-                }
-                catch (IgniteCheckedException e) {
-                    throw new IgniteClientException(ClientStatus.FAILED, e.getMessage(), e);
-                }
+            try {
+                // Give request a chance to be executed and response processed by the current thread,
+                // so we can avoid any performance drops caused by async requests execution.
+                return fut.get(ASYNC_REQUEST_WAIT_TIMEOUT_MILLIS);
             }
-
-            return new ClientAsyncResponse(req0.requestId(), fut);
+            catch (IgniteFutureTimeoutCheckedException ignored) {
+                return new ClientAsyncResponse(req0.requestId(), fut);
+            }
+            catch (IgniteCheckedException e) {
+                throw new IgniteClientException(ClientStatus.FAILED, e.getMessage(), e);
+            }
         }
         else
             return req0.process(ctx);
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/client/thin/BlockingTxOpsTest.java b/modules/core/src/test/java/org/apache/ignite/internal/client/thin/BlockingTxOpsTest.java
index 833767e..0b242d3 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/client/thin/BlockingTxOpsTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/client/thin/BlockingTxOpsTest.java
@@ -245,7 +245,7 @@
             init.run();
 
         GridTestUtils.runMultiThreaded(() -> {
-            for (int i = 0; i < 100; i++) {
+            for (int i = 0; i < 50; i++) {
                 // Mix implicit and explicit transactions.
                 if (ThreadLocalRandom.current().nextBoolean()) {
                     while (true) {