I'm getting a mysterious exception with Ktor clien...
# ktor
k
I'm getting a mysterious exception with Ktor client
2.0.3
with cURL on K/N with the new memory manager on
linuxX64
. It always happens on the second network request for a given "service". Here's an abbreviated stracktrace.
Copy code
Uncaught Kotlin exception: kotlinx.coroutines.JobCancellationException: Parent job is Completed; job=JobImpl{Completed}@162aaa80
    at 0   permit-data.kexe                    0x42fd70           kfun:kotlin.Exception#<init>(kotlin.String?;kotlin.Throwable?){} + 128 
    at 1   permit-data.kexe                    0x42ff20           kfun:kotlin.RuntimeException#<init>(kotlin.String?;kotlin.Throwable?){} + 128 
    at 2   permit-data.kexe                    0x4304a0           kfun:kotlin.IllegalStateException#<init>(kotlin.String?;kotlin.Throwable?){} + 128 
    at 3   permit-data.kexe                    0x43bf30           kfun:kotlin.coroutines.cancellation.CancellationException#<init>(kotlin.String?;kotlin.Throwable?){} + 128
Full stacktrace is in thread. I'm going to keep digging in, Is this perhaps a problems with ktor client?
a
Could you please share a code snippet?
k
Untitled.txt
Here's the client config
Copy code
val httpClient = HttpClient(Curl) {
      install(HttpTimeout)
    }
Here's the service that's problematic.
Copy code
class GeocodeService(
  private val baseUrl: String,
  private val client: HttpClient,
  private val json: Json,
) {

  suspend fun search(
    streetAddress: String,
    postcode: String,
  ): GeocodeResponse? {
    val response = client.get("$baseUrl/search") {
      parameter("street", streetAddress)
      parameter("postalcode", postcode)
      parameter("addressdetails", 1)
    }

    return json.decodeFromString(
      deserializer = ListSerializer(GeocodeResponse.serializer()),
      string = response.bodyAsText(),
    ).firstOrNull()
  }
}
I don't think I'm doing anything particularly fancy
a
And how do you use the
GeocodeService
?
k
Like this.
Copy code
private fun createGeocodingFlow(
    source: Flow<PermitResult>,
    client: HttpClient,
    geocodeProgress: Animation<Address>,
  ): Flow<Pair<PermitResult, GeocodeResponse?>> {
    val service = GeocodeService(nominatimUrl, client, json)
    return source.withIndex().map { (index, record) ->
      record.address?.let { geocodeProgress.update(it) }

      val geocodeResult = record.address?.let { address ->
        service.search(
          address.streetAddress,
          address.postalCode,
        )
      }

      Pair(record, geocodeResult)
    }
  }
source
is a
channelFlow
Copy code
private fun createPermitDataFlow(client: HttpClient): Flow<PermitResult> = channelFlow {
    PermitService(client, json).use { service ->
      coroutineScope {
          PermitType.values().forEach { type ->
            launch {
              service.getPermitData(type).result.permitResults.forEach { permit ->
                send(permit)
              }
            }
          }
        }
      }
    }
  }.buffer(Channel.UNLIMITED)
­čĄŽ I may have forgotten to call
awaitClose
on the channelFlow
Let me check that out.
That's totally the issue. Sorry for the bother, and also thank you for being my rubber duck.
rubber duck 1
­čĹŹ 1