Hi @llooper-dev,
It seems that while running a heavy load of mutations, Dgraph is taking some time to send the response back for some of them and that causes the client to park its threads while waiting for that response as you are using the synchronous client.
You can avoid waiting for the response by using the asynchronous client. AsyncClient will give you AsyncTransaction. Using .mutate() on that transaction will give you a CompletableFuture which lets say you can keep collecting at the client-side in some list.
You can run a separate thread pool on the client to process that list of CompletableFuture. The processing will first check whether the future has completed using .isDone(), if that returns true, you can try .join() to get the Response otherwise you don’t try to .join() it. That way you can completely unblock your main thread. You can configure your thread pool to wake up every second and process the futures. And at the end when you are done with all the mutations, after giving some time-out, you can mark the remaining futures in that list using .completeExceptionally(), so that when you call .join() on them they throw an error.
The ClientInterceptor not working for your case seems like a bug to me with the Java-Client. That I will have to dig deeper and find out a fix. I do suspect these lines though: dgraph4j/StreamObserverBridge.java at master · dgraph-io/dgraph4j · GitHub
I guess what may be happening is the ClientInterceptor calls onCompleted() but that never marks the future as complete, so the thread remains blocked. But, I am not sure about that, so need to dig deeper.