Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #333 Close HTTP connections #334

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,18 @@ class ResponseWrapper(
val url: String,
) : Response by response

fun createHttpClient(): HttpHandler {
private fun createHttpClient(): HttpHandler {
return ClientFilters.FollowRedirects().then(ApacheClient())
}

fun httpRequest(request: Request): ResponseWrapper {
fun <R> httpRequest(request: Request, mapper: (ResponseWrapper) -> R): R {
val client = createHttpClient()
val response = client(request)

return ResponseWrapper(response, request.uri.toString())
return ResponseWrapper(response, request.uri.toString()).use(mapper)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Won't it fix the issue if we just close the response here? I mean

val client = createHttpClient()
val response = client(request)
response.close()
return ResponseWrapper(response, request.uri.toString())

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The connection will be closed of course, but I'm afraid that if you try to access the request's body after that, you'll get an exception

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, it seems that closing the response doesn't help at this point. The returned response object is a MemoryResponse, so closing it is a no-op. The HTTP connection is probably expected to be closed in CloseableHttpResponse.toHttp4kResponse which consumes the entire payload, but again, that doesn't happen in our AWS setup.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@strangepleasures have you checked that the edits you have introduced fix the issue in your AWS setup?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can provide you with pip package if you need

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ApacheClient() without arguments creates a client with a PoolingHttpClientConnectionManager with infinite TTL. Maybe, that's why connections never get closed.

}

fun getHttp(url: String) = httpRequest(Request(Method.GET, url))
fun <R> getHttp(url: String, mapper: (ResponseWrapper) -> R): R = httpRequest(Request(Method.GET, url), mapper)

fun Request.withBasicAuth(username: String, password: String): Request {
val b64 = Base64.getEncoder().encode("$username:$password".toByteArray()).toString(Charsets.UTF_8)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ class LibraryDescriptorsManager private constructor(
url += "&since=$sinceTimestamp"
}
logger.info("Checking for new commits to library descriptors at $url")
val arr = getHttp(url).jsonArrayOrNull
val arr = getHttp(url) { it.jsonArrayOrNull }
if (arr == null) {
logger.error("Request for the latest commit in libraries failed")
return@catchAll null
Expand Down Expand Up @@ -91,8 +91,7 @@ class LibraryDescriptorsManager private constructor(
}

fun checkRefExistence(ref: String): Boolean {
val response = getHttp("$apiPrefix/contents/$remotePath?ref=$ref")
return response.status.successful
return getHttp("$apiPrefix/contents/$remotePath?ref=$ref") { it.status.successful }
}

fun checkIfRefUpToDate(remoteRef: String?): Boolean {
Expand All @@ -110,7 +109,7 @@ class LibraryDescriptorsManager private constructor(

val url = "$apiPrefix/contents/$remotePath?ref=$ref"
logger.info("Requesting library descriptors at $url")
val response = getHttp(url).jsonArray
val response = getHttp(url) { it.jsonArray }

for (item in response) {
item as JsonObject
Expand All @@ -120,9 +119,8 @@ class LibraryDescriptorsManager private constructor(
if (!fileName.endsWith(".$DESCRIPTOR_EXTENSION")) continue

val downloadUrl = item["download_url"]!!.jsonPrimitive.content
val descriptorResponse = getHttp(downloadUrl)

val descriptorText = descriptorResponse.text
val descriptorText = getHttp(downloadUrl) { it.text }
val file = localLibrariesDir.resolve(fileName)
file.writeText(descriptorText)
}
Expand All @@ -144,10 +142,9 @@ class LibraryDescriptorsManager private constructor(
}

private fun downloadSingleFile(contentsApiUrl: String): String {
val response = getHttp(contentsApiUrl).jsonObject
val response = getHttp(contentsApiUrl) { it.jsonObject }
val downloadUrl = response["download_url"]!!.jsonPrimitive.content
val res = getHttp(downloadUrl)
return res.text
return getHttp(downloadUrl) { it.text }
}

private fun saveLocalRef(ref: String) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,10 @@ class KernelVersionUpdateTasksConfigurator(
val teamcityUrl = teamcityProject.url
val locator = "buildType:(id:${teamcityProject.projectId}),status:SUCCESS,branch:default:any,count:1"

val response = httpRequest(
val builds = httpRequest(
Request(Method.GET, "$teamcityUrl/$TEAMCITY_REQUEST_ENDPOINT/?locator=$locator")
.header("accept", "application/json")
)
val builds = response.jsonObject["build"] as JsonArray
) { it.jsonObject["build"] as JsonArray }
val lastBuild = builds[0] as JsonObject
val lastBuildNumber = (lastBuild["number"] as JsonPrimitive).content
println("Last Kotlin dev version: $lastBuildNumber")
Expand Down
40 changes: 19 additions & 21 deletions build-plugin/src/build/LibraryUpdateTasksConfigurator.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import org.gradle.process.ExecSpec
import org.gradle.tooling.BuildException
import org.http4k.core.Method
import org.http4k.core.Request
import org.http4k.core.Response
import org.jetbrains.kotlinx.jupyter.common.ResponseWrapper
import org.jetbrains.kotlinx.jupyter.common.httpRequest
import org.jetbrains.kotlinx.jupyter.common.jsonObject
Expand Down Expand Up @@ -99,25 +98,21 @@ class LibraryUpdateTasksConfigurator(
val user = settings.prGithubUser
val password = settings.prGithubToken
val repoUserAndName = settings.librariesRepoUserAndName
fun githubRequest(
fun <R> githubRequest(
method: Method,
request: String,
json: JsonElement,
onFailure: (Response) -> Unit,
): ResponseWrapper {
val response = httpRequest(
Request(method, "https://api.github.com/$request")
.withJson(json)
.withBasicAuth(user, password)
)
println(response.text)
if (!response.status.successful) {
onFailure(response)
}
return response
mapper: (ResponseWrapper) -> R
): R = httpRequest(
Request(method, "https://api.github.com/$request")
.withJson(json)
.withBasicAuth(user, password)
) {
println(it.text)
mapper(it)
}

val prResponse = githubRequest(
val prNumber = githubRequest(
Method.POST, "repos/$repoUserAndName/pulls",
Json.encodeToJsonElement(
NewPrData(
Expand All @@ -126,18 +121,21 @@ class LibraryUpdateTasksConfigurator(
base = "master"
)
)
) { response ->
throw BuildException("Creating PR failed with code ${response.status.code}", null)
) {
if (!it.status.successful) {
throw BuildException("Creating PR failed with code ${it.status.code}", null)
}
(it.jsonObject["number"] as JsonPrimitive).int
}

val prNumber = (prResponse.jsonObject["number"] as JsonPrimitive).int
githubRequest(
Method.POST, "repos/$repoUserAndName/issues/$prNumber/labels",
Json.encodeToJsonElement(
SetLabelsData(listOf("no-changelog", "library-descriptors"))
)
) { response ->
throw BuildException("Cannot setup labels for created PR: ${response.text}", null)
) {
if (!it.status.successful) {
throw BuildException("Cannot setup labels for created PR: ${it.text}", null)
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ class Image(private val attributes: List<HTMLAttr>) : Renderable {
val client = ApacheClient()
val request = Request(Method.GET, url)
val response = client(request)
return response.body.payload.array()
return response.use { it.body.payload.array() }
}

fun loadData(file: File): ByteArray {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class CssLibraryResourcesProcessor : LibraryResourcesProcessor {
ResourcePathType.URL -> """
<link rel="stylesheet" href="$path">
""".trimIndent()
ResourcePathType.URL_EMBEDDED -> wrapInTag(getHttp(path).text)
ResourcePathType.URL_EMBEDDED -> getHttp(path) { wrapInTag(it.text) }
ResourcePathType.LOCAL_PATH -> wrapInTag(File(path).readText())
ResourcePathType.CLASSPATH_PATH -> wrapInTag(classLoader.getResource(path)?.readText().orEmpty())
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class JsLibraryResourcesProcessor : LibraryResourcesProcessor {
URLScriptModifierFunctionGenerator(path)
}
ResourcePathType.URL_EMBEDDED -> {
val scriptText = getHttp(path).text
val scriptText = getHttp(path) { it.text }
CodeScriptModifierFunctionGenerator(scriptText)
}
ResourcePathType.LOCAL_PATH -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ class StandardResolutionInfoProvider(override var fallback: LibraryResolutionInf
}

private fun tryGetAsURL(url: String): LibraryResolutionInfo? {
val response = getHttp(url)
return if (response.status.successful) AbstractLibraryResolutionInfo.ByURL(URL(url)) else null
return getHttp(url) { if (it.status.successful) AbstractLibraryResolutionInfo.ByURL(URL(url)) else null }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,7 @@ object FallbackLibraryResolver : ChainedLibraryResolver() {
file.readText()
},
resolver<AbstractLibraryResolutionInfo.ByURL> {
val response = getHttp(url.toString())
response.text
getHttp(url.toString()) { it.text }
},
resolver<ByNothingLibraryResolutionInfo> { "{}" },
resolver<AbstractLibraryResolutionInfo.Default> { null }
Expand Down