Open steven-sheehy opened 1 year ago
It's even worse than originally believed because SubscriptionHandle.unsubscribe()
is asynchronous. So even manually unsubscribing first doesn't guarantee that it completes before Client.close()
. In general, Client.close()
seems to have multiple issues and can hang until timeout is reached.
I am using latest version of the library (v2.27.0) and getting this error sometimes. What should be the possible solution? I am using below code.
fun getTransactionReceiptInfo(txnIdValue: ByteArray, onSuccess: (String?) -> Unit) {
val client = getClient()
try {
val txnId = TransactionId.fromBytes(txnIdValue)
TransactionReceiptQuery().setTransactionId(txnId).executeAsync(client).thenAccept {
onSuccess(it.toBytes().toBase64String())
}
} catch (e: Exception) {
onSuccess(null)
} finally {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
client.close(Duration.ofMillis(10000))
} else {
client.close()
}
}
}
FATAL EXCEPTION: DefaultDispatcher-worker-9 Process: cc.dropp.wallet, PID: 11111 java.util.concurrent.TimeoutException: Failed to properly shutdown all channels at com.hedera.hashgraph.sdk.BaseNetwork.awaitClose(BaseNetwork.java:573) at com.hedera.hashgraph.sdk.Client.close(Client.java:1359) at com.opencrowd.drop.common.HederaHashgraphManager.getTransactionReceiptInfo(HederaHashgraphManager.kt:94) at com.opencrowd.drop.ui.MainActivity.handleQueryRequest(MainActivity.kt:414) at com.opencrowd.drop.ui.MainActivity.access$handleQueryRequest(MainActivity.kt:55) at com.opencrowd.drop.ui.MainActivity$onStart$walletDelegate$1.onSessionRequest(MainActivity.kt:271) at com.walletconnect.web3.wallet.client.Web3Wallet$setWalletDelegate$signWalletDelegate$1.onSessionRequest(Web3Wallet.kt:43) at com.walletconnect.sign.client.SignProtocol$setWalletDelegate$1.invokeSuspend(SignProtocol.kt:56) at com.walletconnect.sign.client.SignProtocol$setWalletDelegate$1.invoke(Unknown Source:8) at com.walletconnect.sign.client.SignProtocol$setWalletDelegate$1.invoke(Unknown Source:4) at kotlinx.coroutines.flow.FlowKt__TransformKt$onEach$$inlined$unsafeTransform$1$2.emit(Emitters.kt:223) at kotlinx.coroutines.flow.SharedFlowImpl.collect$suspendImpl(SharedFlow.kt:383) at kotlinx.coroutines.flow.SharedFlowImpl$collect$1.invokeSuspend(Unknown Source:15) at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33) at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106) at kotlinx.coroutines.internal.LimitedDispatcher.run(LimitedDispatcher.kt:42) at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:95) at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:570) at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750) at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:677) at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:664)
Description
Attempting to close a
Client
in the middle of a mirror node gRPC API streaming query will block forcloseTimeout
then throw a timeout exception. Since you can't have a subscription without theChannel
that theClient
manages for it, it's expected that the SDK would register any subscriptions and close them gracefully onclose()
. Requiring the user to manually unsubscribe from the gRPC query is awkward and error-prone since it can only unsubscribe during the happy path or if close is called manually. In the below, it can't just unsubscribe once in a finally block.Steps to reproduce
Additional context
Hedera network
mainnet
Version
v2.18.0
Operating system
No response