해결된 질문
작성
·
20
0
- 학습 관련 질문을 남겨주세요. 질문을 상세히 작성하면 더 좋습니다.
- 서로 예의를 지키며 존중하는 문화를 만들어가요.
- 잠깐! 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요.
안녕하세요, coroutine 강의를 듣고 ktor server 공부를 하는 중에 delay 관련 질의가 생겨 글 남깁니다.
delay 의 경우 coroutine 이 스레드를 양보하고, 일정 시간 후에 다시 스레드가 비어있으면 점유하는 형식으로 진행될텐데, 아래와 같은 경우 delay 이후 코드가 실행되지 않습니다.
사용자 → KTOR Server → suspend function call → loop { logic → 너무 많은 동작을 제한하기위한 delay }
ktor 는 기본적으로 요청이 IO Dispatcher 를 사용하는 것 같은데, coroutine 에서 delay 이후 기능이 동작하지 않는 것에 대한 이유가 있을까요..? (강의랑 무관한 내용이라 죄송합니다 ㅠ.ㅠ)
/* Routing.kt */
fun Application.configureRouting(searcher: BaseSearcher) {
routing {
post("/search") {
val params = call.receive<Map<String, String>>()
searcher.logging("Received POST request with params: $params")
val result: List<BaseDTO> = searcher.search(params)
searcher.logging("POST Result: $result")
call.respond(HttpStatusCode.OK, mapOf("result" to result))
}
get("/") {
call.respondText("Hello World!")
}
}
}
/* Searcher.kt */
/**
* 함수 이름 : search
* 내용 설명 : 입력된 map<string, string> param 을 바탕으로 요청 전송 및 응답 반환
*/
override suspend fun search(searchParam: Map<String, String>): List<SimpleSearchLandResultDTO> {
// 별도의 Job 으로 분리해서 오류시 상위 전파 제한
return HttpClient(CIO).use { client ->
val parseResultLst: MutableList<SimpleSearchLandResultDTO> = mutableListOf()
try {
val initRequestResultDto: SimpleSearchResultDTO =
sendFormedRequest(client, SearcherConst.URL_MAIN_PAGE, false)
// 기본 페이지 요청이 성공했을 때 다음 요청을 진행
if (initRequestResultDto.isSuccess) {
val mutableSearchParam = searchParam.toMutableMap()
delay(300)
while (true) {
val eachPageSearchResultDto: SimpleSearchResultDTO =
sendFormedRequest(client, makeGetUrl(mutableSearchParam), true)
// 실패한 경우 종료
if (!eachPageSearchResultDto.isSuccess) {
logging("[search] 조회 중 오류가 발생하였습니다.")
break
}
// 결과가 빈 경우도 종료
else if (eachPageSearchResultDto.landSearchResultLst.isEmpty()) {
break
}
// 결과가 있는 경우엔 전부 더해줌
parseResultLst.addAll(eachPageSearchResultDto.landSearchResultLst)
logging("[search] result(${eachPageSearchResultDto.landSearchResultLst[0].currentPage} : ${eachPageSearchResultDto.landSearchResultLst}")
// 마지막 페이지인 경우 종료
if (eachPageSearchResultDto.landSearchResultLst[0].currentPage ==
eachPageSearchResultDto.landSearchResultLst[0].maxPage
) {
break
} else {
// 다음 페이지 수집 진행
mutableSearchParam["currentPage"] =
(eachPageSearchResultDto.landSearchResultLst[0].currentPage + 1).toString()
delay(300)
}
}
}
} catch (e: Exception) {
logging("[search] search 함수 중 오류가 발생하였습니다. param: $searchParam, exception: $e")
}
logging("[search] Result : $parseResultLst")
// parseResultLst 반환
parseResultLst
}
}
private suspend fun sendFormedRequest(client: HttpClient, url: String, isResultNeed: Boolean): SimpleSearchResultDTO {
return try {
val response = client.get(url) {
headers {
append(HttpHeaders.Cookie, cookie.toCookieString())
append(HttpHeaders.Accept, SearcherConst.DEFAULT_HTTP_ACCEPT)
append(HttpHeaders.AcceptEncoding, SearcherConst.DEFAULT_HTTP_ACCEPT_ENCODING)
append(HttpHeaders.Connection, SearcherConst.DEFAULT_HTTP_CONNECTION)
append(HttpHeaders.AcceptLanguage, SearcherConst.DEFAULT_HTTP_ACCEPT_LANGUAGE)
append(HttpHeaders.UserAgent, SearcherConst.DEFAULT_HTTP_USER_AGENT)
}
}
cookie.putAll(response.headers[HttpHeaders.SetCookie]?.split(";")?.map { it.split("=") }?.
filter { it.size == 2 }?.filter { it[1] != "/" && it[1].isNotEmpty() }?.associate { it[0] to it[1] } ?: mapOf())
if (response.status != HttpStatusCode.OK) {
SimpleSearchResultDTO(false)
} else {
SimpleSearchResultDTO(true, if(isResultNeed) parseData(response.bodyAsText()) else mutableListOf())
}
} catch(e: Exception) {
logging("[sendFormedRequest] Error : $e", Level.ERROR)
SimpleSearchResultDTO(false)
}
}
답변 2
0
kokoxg2님 안녕하세요. 지식 공유자 조세영입니다.
제가 ktor를 실제로 사용해본 적이 없어 코드 흐름만 보고 답변 드립니다.
질문 주신 코드만으로는 delay 이후 코드의 동작을 제한하는 부분이 없는 것 같아 보이는데요. delay 이후 코드가 동작하지 않는 다는건 너무 다양한 문제가 있기 때문에(모든 스레드 블로킹, 예외 발생으로 취소돼 동작하지 않는 것처럼 보이는 것, delay 재개 이후 코드에서 일시중단 후 재개 하지 않음, delay 도중 코루틴이취소됨 등) 정확한 부분은 디버깅을 해봐야 알 수 있을 것 같습니다.
도움이 되었으면 좋을 것 같습니다. 감사합니다.
0
안녕하세요, 인프런 AI 인턴입니다. kokoxg2님.
Ktor 서버 환경에서 delay
함수 사용 후 실행되지 않는 현상에 대해 질문 주셔서 감사합니다. delay
함수는 코루틴이 특정 시간 동안 대기하도록 하지만 스레드를 점유하지 않으며 다른 코루틴이 실행될 수 있도록 합니다. 그러나, IO Dispatcher
와 같은 환경에서는 여러 가지 이유로 인해 기대한 대로 작동하지 않을 수 있습니다. 가능한 몇 가지 원인을 요약하여 말씀드리겠습니다.
스레드 제한 문제:
코루틴 범위 및 실행 문제:
search
함수 내에서 launch
등의 코루틴 빌더를 사용하여 실행 컨텍스트 문제를 해결해 보세요.중복처리 문제:
Exception Handling:
try-catch
구문으로 감싸져 있어 오류 시 작성한 예외 처리가 오는 경우 이어서 실행되지 않을 수 있습니다. 예상치 못한 곳에서 예외가 발생하진 않는지 확인하세요.HTTP 클라이언트의 사용 문제:
HttpClient
를 사용할 때, 비동기 호출함에 있어 사용한 API가 실제로 논블로킹 방식을 지원하는지 확인이 필요합니다.관련된 내용에 대한 이해를 더 돕기 위해 코루틴 공식 문서를 참조해 보실 것을 추천드립니다.
저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다. 현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏 추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.