Мультиплатформенный Kotlin: исключение JobCancellationException: родительское задание завершено

#kotlin #kotlin-coroutines #ktor

#kotlin #kotlin-сопрограммы #ktor

Вопрос:

Я пытаюсь написать мультиплатформенную библиотеку kotlin (Android и ios), которая использует ktor. Таким образом, у меня возникают некоторые проблемы с сопрограммами kotlin:

 When writing tests I always get kotlinx.coroutines.JobCancellationException: Parent job is Completed; job=JobImpl{Completed}@... exception.
 

Я использую движок ktors для своих тестов:

 client = HttpClient(MockEngine) 
{
    engine 
    {
         addHandler 
         { request ->
             // Create response object
         }
     }
}
 

Примерный метод (модуль commonMain) с использованием ktor. Все методы в моей библиотеке написаны аналогичным образом. Исключение возникает, если вызывается client.get .

 suspend fun getData(): Either<Exception, String> = coroutineScope 
{
     // Exception occurs in this line:
     val response: HttpResponse = client.get { url("https://www.google.com") }

     return if (response.status == HttpStatusCode.OK) 
     {
         (response.readText() as T).right()
     } 
     else 
     {
        Exception("Error").left()
     }
}
 

Пример модульного теста (модуль commonTest) для вышеуказанного метода. Оператор assertTrue никогда не вызывается, поскольку исключение генерируется ранее.

 @Test
fun getDataTest() = runTest 
{
    val result = getData()
    assertTrue(result.isRight())
}
 

Фактическая реализация runTest в модулях androidTest и iosTest.

 actual fun<T> runTest(block: suspend () -> T) { runBlocking { block() } }
 

Я думал, что когда я использую CoroutineScope, он ждет, пока не будут выполнены все дочерние сопрограммы. Что я делаю не так и как я могу исправить это исключение?

Комментарии:

1. Вы нашли решение?

2. область действия сопрограммы, насколько я знаю, отменит другие сопрограммы. Если вы хотите отделить родительское задание от других заданий, вы можете использовать CoroutineScope.launch или вызвать call с областью действия супервизора

Ответ №1:

вы не можете кэшировать HttpClient ИТ-директора в переменной клиента и повторно использовать, было бы лучше, если бы изменить следующий код в вашей реализации.

 val client:HttpClient get() = HttpClient(MockEngine) {
    engine {
         addHandler { request ->
             // Create response object
         }
     }
}
 

Комментарии:

1. Не ясно. Предоставьте дополнительную информацию

2. Комментарий означает, что если вы сохраните HttpClient в val, например, val client:HttpClient get() = HttpClient(Android), это также может привести к исключению JobCancellationException. Однако, если вы возвращаете новый экземпляр клиента каждый раз, когда получаете доступ к значению (это было get()) ), проблема исчезнет. По крайней мере, моя проблема может быть решена с помощью этого незначительного изменения.

Ответ №2:

Библиотека должна быть обновлена, этот сбой находится в отчете об исправлении здесь: https://newreleases.io/project/github/ktorio/ktor/release/1.6.1

Комментарии:

1. Определенно исправил это для меня, начиная с версии 1.5.2

2. Рад помочь, приятель

Ответ №3:

Проблема в том, что вы не можете использовать один и тот же экземпляр HttpClient. Мой ej:

 HttpClient(CIO) {
                install(JsonFeature) {
                    serializer = GsonSerializer()
                }
            }.use { client ->
                return@use client.request("URL") {
                    method = HttpMethod.Get
                }
            }