cashapp/zipline

Crashes on cancelling suspending functions in a usecase.

Opened this issue · 6 comments

Fatal Exception: v6.g: no such service (service closed?)
	called service:
		zipline/guest-14
	available services:
		zipline/guest
		CustomZiplineService
       at app.cash.zipline.internal.bridge.OutboundCallHandler.withApiMismatchMessage-KWTtemM(OutboundCallHandler.java:297)
       at app.cash.zipline.internal.bridge.OutboundCallHandler.access$withApiMismatchMessage-KWTtemM(OutboundCallHandler.java:80)
       at app.cash.zipline.internal.bridge.OutboundCallHandler$call$2.invoke(OutboundCallHandler.java:80)
       at app.cash.zipline.internal.bridge.Endpoint.withTakeScope$zipline_release(Endpoint.java:138)
       at app.cash.zipline.internal.bridge.OutboundCallHandler.call(OutboundCallHandler.java:138)
       at app.cash.zipline.internal.bridge.CancelCallback$Companion$Adapter$GeneratedOutboundService.cancel(CancelCallback.java:5)
       at app.cash.zipline.internal.bridge.OutboundCallHandler$callSuspending$3$1$1.invokeSuspend(OutboundCallHandler.java:12)
       at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(BaseContinuationImpl.java:12)
       at kotlinx.coroutines.DispatchedTask.run(:89)
       at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
       at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
       at java.lang.Thread.run(Thread.java:923)

Any ideas/hints toward what diagnostics ?

This is typically caused by calling close and then using a service. We can improve the error message to include the type of service you’re calling.

I am not explicitly closing any service in app session.

since services are needed throughout the app session 🤔, although yes better error reports would also be a plus, but still If I were to handle this error where is the place I need to do so ?

wrapping zipline.take try/catch ?

I got lucky and am able to repro in one case, but still don't have a pretty clear understanding why,
My code looks like below:

interface CustomZiplineService {
  suspend fun search(query: String): List<Entity>
}

now in my code I am running zipline from Application class, and taking said service there.

in my SearchComponent, I search local and remote zipline services and emit their result in a flow.


class SearchComponent {

  var searchJob: Job? = null

  fun search(query: String): Flow<List<Entity>> = flow {
    val list: List<Entity> = mutableListOf()
     supervisorScope {
         launch { 
             searchLocal(query).also { list.addAll(it) }
             emit(list)
         }

        launch {
           withContext(ziplineDispatcher) {
                ExtensionManager.service.search(query).also { list.addAll(it) }
                emit(list)
            }
         }
      }
   }


   fun runSearch(query: String) {
        searchJob?.cancel() // **THIS LEADS TO CRASH**
        searchJob = lifecycleScope.launch {
             search(query).collectLatest {
                // skipping app impl details
             }
        }
    }
}

Can confirm the crash is consistently coming, whenever a suspending call from service is cancelled within host's coroutine.

lmk, If I can help with more details.

app.cash.zipline.ZiplineException: CompletionHandlerException: Exception in completion handler InvokeOnCompletion@1[job@2] for DeferredCoroutine{Completed}@2
                                                                                                    	at captureStack (runtime/coreRuntime.kt:86)
                                                                                                    	at CompletionHandlerException (mnt/agent/work/44ec6e850d5c63f0/kotlinx-coroutines-core/common/src/Exceptions.common.kt:1664)
                                                                                                    	at notifyCompletion (mnt/agent/work/44ec6e850d5c63f0/kotlinx-coroutines-core/common/src/JobSupport.kt:158)
                                                                                                    	at completeStateFinalization (mnt/agent/work/44ec6e850d5c63f0/kotlinx-coroutines-core/common/src/JobSupport.kt:325)
                                                                                                    	at finalizeFinishingState (mnt/agent/work/44ec6e850d5c63f0/kotlinx-coroutines-core/common/src/JobSupport.kt:236)
                                                                                                    	at tryMakeCompletingSlowPath (mnt/agent/work/44ec6e850d5c63f0/kotlinx-coroutines-core/common/src/JobSupport.kt:910)
                                                                                                    	at tryMakeCompleting (mnt/agent/work/44ec6e850d5c63f0/kotlinx-coroutines-core/common/src/JobSupport.kt:867)
                                                                                                    	at <anonymous> (mnt/agent/work/44ec6e850d5c63f0/kotlinx-coroutines-core/common/src/JobSupport.kt:832)
                                                                                                    	at <anonymous> (mnt/agent/work/44ec6e850d5c63f0/kotlinx-coroutines-core/common/src/AbstractCoroutine.kt:99)
                                                                                                    	at <anonymous> (src/kotlin/coroutines_13/CoroutineImpl.kt:79)
                                                                                                    	at <anonymous> (kotlin-kotlin-stdlib-js-ir.js)
                                                                                                    	at <anonymous> (mnt/agent/work/44ec6e850d5c63f0/kotlinx-coroutines-core/common/src/internal/DispatchedTask.kt:51)
                                                                                                    	at <anonymous> (mnt/agent/work/44ec6e850d5c63f0/kotlinx-coroutines-core/js/src/JSDispatcher.kt:155)
                                                                                                    	at <anonymous> (mnt/agent/work/44ec6e850d5c63f0/kotlinx-coroutines-core/js/src/JSDispatcher.kt)
                                                                                                    	at apply (native)
                                                                                                    	at <anonymous> (runner/work/zipline/zipline/zipline/src/jsMain/kotlin/app/cash/zipline/GlobalBridge.kt:72)
                                                                                                    	at <anonymous> (runner/work/zipline/zipline/zipline/src/commonMain/kotlin/app/cash/zipline/internal/GuestService.kt)
                                                                                                    	at <anonymous> (zipline-root-zipline.js)
                                                                                                    	at <anonymous> (runner/work/zipline/zipline/zipline/src/commonMain/kotlin/app/cash/zipline/internal/bridge/InboundService.kt:53)
                                                                                                    	at <anonymous> (runner/work/zipline/zipline/zipline/src/commonMain/kotlin/app/cash/zipline/internal/bridge/Endpoint.kt:99)
                                                                                                    	at <anonymous> (zipline-root-zipline.js)
                                                                                                    	at <anonymous> (runner/work/zipline/zipline/zipline/src/jsMain/kotlin/app/cash/zipline/GlobalBridge.kt)
                                                                                                    	at <anonymous> (zipline-root-zipline.js)
                                                                                                        Suppressed: DiagnosticCoroutineContextException: [DeferredCoroutine{Completed}@2, SetTimeoutDispatcher@3]
                                                                                                    	at captureStack (runtime/coreRuntime.kt:86)
                                                                                                    	at DiagnosticCoroutineContextException (mnt/agent/work/44ec6e850d5c63f0/kotlinx-coroutines-core/js/src/internal/CoroutineExceptionHandlerImpl.kt:8930)
                                                                                                    	at handleUncaughtCoroutineException (mnt/agent/work/44ec6e850d5c63f0/kotlinx-coroutines-core/common/src/internal/CoroutineExceptionHandlerImpl.common.kt:46)
                                                                                                    	at handleCoroutineException (mnt/agent/work/44ec6e850d5c63f0/kotlinx-coroutines-core/common/src/CoroutineExceptionHandler.kt:32)
                                                                                                    	at <anonymous> (mnt/agent/work/44ec6e850d5c63f0/kotlinx-coroutines-core/common/src/AbstractCoroutine.kt:107)
                                                                                                    	at notifyCompletion (mnt/agent/work/44ec6e850d5c63f0/kotlinx-coroutines-core/common/src/JobSupport.kt:158)
                                                                                                            ... and 21 more common stack frames skipped
                                                                                                    Caused by:     at captureStack (runtime/coreRuntime.kt:86)
                                                                                                    	at ClassCastException_init_$Create$ (kotlin-kotlin-stdlib-js-ir.js)
                                                                                                    	at THROW_CCE (runtime/hacks.kt)
                                                                                                    	at <anonymous> (soundbound-extensions-lib.js)
                                                                                                    	at <anonymous> (opt/buildAgent/work/b2fef8360e1bcf3d/formats/json/commonMain/src/kotlinx/serialization/json/internal/Polymorphic.kt:20)
                                                                                                    	at <anonymous> (opt/buildAgent/work/b2fef8360e1bcf3d/core/commonMain/src/kotlinx/serialization/encoding/AbstractEncoder.kt:80)
                                                                                                    	at <anonymous> (opt/buildAgent/work/b2fef8360e1bcf3d/core/commonMain/src/kotlinx/serialization/internal/CollectionSerializers.kt:68)
                                                                                                    	at <anonymous> (kotlinx-serialization-kotlinx-serialization-core-js-ir.js)
                                                                                                    	at <anonymous> (opt/buildAgent/work/b2fef8360e1bcf3d/formats/json/commonMain/src/kotlinx/serialization/json/internal/Polymorphic.kt:20)
2023-08-15 20:28:53.608 16363-16440 Zipline                 in.shabinder.soundbound.preview      E  	at <anonymous> (opt/buildAgent/work/b2fef8360e1bcf3d/core/commonMain/src/kotlinx/serialization/encoding/AbstractEncoder.kt:80)
                                                                                                    	at <anonymous> (commonMainSources/libraries/stdlib/src/kotlin/util/Preconditions.kt:234)
                                                                                                    	at <anonymous> (zipline-root-zipline.js)
                                                                                                    	at <anonymous> (opt/buildAgent/work/b2fef8360e1bcf3d/formats/json/commonMain/src/kotlinx/serialization/json/internal/Polymorphic.kt:20)
                                                                                                    	at <anonymous> (opt/buildAgent/work/b2fef8360e1bcf3d/core/commonMain/src/kotlinx/serialization/encoding/AbstractEncoder.kt:80)
                                                                                                    	at <anonymous> (opt/buildAgent/work/b2fef8360e1bcf3d/core/commonMain/src/kotlinx/serialization/encoding/Encoding.kt:341)
                                                                                                    	at <anonymous> (zipline-root-zipline.js)
                                                                                                    	at <anonymous> (opt/buildAgent/work/b2fef8360e1bcf3d/formats/json/commonMain/src/kotlinx/serialization/json/internal/Polymorphic.kt:20)
                                                                                                    	at encodeToDynamic_0 (opt/buildAgent/work/b2fef8360e1bcf3d/formats/json/jsMain/src/kotlinx/serialization/json/internal/DynamicEncoders.kt:42)
                                                                                                    	at encodeToDynamic (opt/buildAgent/work/b2fef8360e1bcf3d/formats/json/jsMain/src/kotlinx/serialization/json/Dynamics.kt)
                                                                                                    	at encodeToStringFast (runner/work/zipline/zipline/zipline/src/jsMain/kotlin/app/cash/zipline/internal/jsonJs.kt)
                                                                                                    	at <anonymous> (runner/work/zipline/zipline/zipline/src/commonMain/kotlin/app/cash/zipline/internal/bridge/CallCodec.kt:56)
                                                                                                    	at <anonymous> (runner/work/zipline/zipline/zipline/src/commonMain/kotlin/app/cash/zipline/internal/bridge/OutboundCallHandler.kt:83)
                                                                                                    	at <anonymous> (runner/work/zipline/zipline/zipline/src/commonMain/kotlin/app/cash/zipline/internal/bridge/SuspendCallback.kt)
                                                                                                    	at <anonymous> (zipline-root-zipline.js)
                                                                                                    	at <anonymous> (runner/work/zipline/zipline/zipline/src/commonMain/kotlin/app/cash/zipline/internal/bridge/InboundService.kt:53)
                                                                                                    	at <anonymous> (mnt/agent/work/44ec6e850d5c63f0/kotlinx-coroutines-core/common/src/JobSupport.kt)
                                                                                                    	at <anonymous> (kotlinx.coroutines-kotlinx-coroutines-core-js-ir.js)
                                                                                                    	at notifyCompletion (mnt/agent/work/44ec6e850d5c63f0/kotlinx-coroutines-core/common/src/JobSupport.kt:369)
                                                                                                    	at completeStateFinalization (mnt/agent/work/44ec6e850d5c63f0/kotlinx-coroutines-core/common/src/JobSupport.kt:325)
                                                                                                        ... and 20 more common stack frames skipped
                                                                                                    	at app.cash.zipline.internal.GuestService$Companion$Adapter$GeneratedOutboundService.runJob(GuestService.kt:23)
                                                                                                    	at app.cash.zipline.internal.CoroutineEventLoop$DelayedJob$run$1.invokeSuspend(CoroutineEventLoop.kt:61)
                                                                                                    	at app.cash.zipline.internal.CoroutineEventLoop$DelayedJob$run$1.invoke(Unknown Source:8)
                                                                                                    	at app.cash.zipline.internal.CoroutineEventLoop$DelayedJob$run$1.invoke(Unknown Source:4)
                                                                                                    	at kotlinx.coroutines.intrinsics.UndispatchedKt.startCoroutineUndispatched(Undispatched.kt:44)
                                                                                                    	at kotlinx.coroutines.CoroutineStart.invoke(CoroutineStart.kt:112)
                                                                                                    	at kotlinx.coroutines.AbstractCoroutine.start(AbstractCoroutine.kt:126)
                                                                                                    	at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch(Builders.common.kt:56)
                                                                                                    	at kotlinx.coroutines.BuildersKt.launch(Unknown Source:1)
                                                                                                    	at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch$default(Builders.common.kt:47)
                                                                                                    	at kotlinx.coroutines.BuildersKt.launch$default(Unknown Source:1)
                                                                                                    	at app.cash.zipline.internal.CoroutineEventLoop$DelayedJob.run(CoroutineEventLoop.kt:58)
                                                                                                    	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1137)
                                                                                                    	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:637)
                                                                                                    	at java.lang.Thread.run(Thread.java:1012)
                                                                                                    	
                                                                                   

Recieved these exceptions alongside, if it helps in pointing out where the issue is.
I am at an end, will need some guidance, of where I should look exactly.

from digging and experimenting a bit more, the crash only happens if I use Json{} from kotlinx.serialization for encoding/decoding in my zipline service.
Hmmm, strange 🤔