Skip to content

Commit 9c1603f

Browse files
Merge pull request #199 from statsig-io/close_response
Manually close network connection
2 parents f730341 + 15a0aed commit 9c1603f

File tree

2 files changed

+72
-58
lines changed

2 files changed

+72
-58
lines changed

src/main/kotlin/com/statsig/sdk/SpecStore.kt

Lines changed: 68 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import kotlinx.coroutines.flow.Flow
1111
import kotlinx.coroutines.flow.flow
1212
import kotlinx.coroutines.joinAll
1313
import kotlinx.coroutines.launch
14+
import okhttp3.Response
1415
import kotlin.collections.HashMap
1516

1617
const val STORAGE_ADAPTER_KEY = "statsig.cache"
@@ -130,75 +131,82 @@ internal class SpecStore constructor(
130131
}
131132

132133
private suspend fun syncIdListsFromNetwork() {
133-
val response = network.post(
134-
options.api + "/get_id_lists",
135-
mapOf("statsigMetadata" to statsigMetadata),
136-
emptyMap(),
137-
this.options.initTimeoutMs,
138-
) ?: return
139-
if (!response.isSuccessful) {
140-
return
141-
}
142-
val body = response.body ?: return
143-
val jsonResponse = gson.fromJson<Map<String, IDList>>(body.string()) ?: return
144-
diagnostics.markStart(KeyType.GET_ID_LIST_SOURCES, StepType.PROCESS, additionalMarker = Marker(idListCount = jsonResponse.size))
145-
val tasks = mutableListOf<Job>()
146-
147-
for ((name, serverList) in jsonResponse) {
148-
var localList = idLists[name]
149-
if (localList == null) {
150-
localList = IDList(name = name)
151-
idLists[name] = localList
152-
}
153-
if (serverList.url == null || serverList.fileID == null || serverList.creationTime < localList.creationTime) {
154-
continue
134+
var response: Response? = null
135+
try {
136+
response = network.post(
137+
options.api + "/get_id_lists",
138+
mapOf("statsigMetadata" to statsigMetadata),
139+
emptyMap(),
140+
this.options.initTimeoutMs,
141+
) ?: return
142+
if (!response.isSuccessful) {
143+
return
155144
}
145+
val body = response.body ?: return
146+
val jsonResponse = gson.fromJson<Map<String, IDList>>(body.string()) ?: return
147+
diagnostics.markStart(KeyType.GET_ID_LIST_SOURCES, StepType.PROCESS, additionalMarker = Marker(idListCount = jsonResponse.size))
148+
val tasks = mutableListOf<Job>()
149+
150+
for ((name, serverList) in jsonResponse) {
151+
var localList = idLists[name]
152+
if (localList == null) {
153+
localList = IDList(name = name)
154+
idLists[name] = localList
155+
}
156+
if (serverList.url == null || serverList.fileID == null || serverList.creationTime < localList.creationTime) {
157+
continue
158+
}
159+
160+
// check if fileID has changed, and it is indeed a newer file. If so, reset the list
161+
if (serverList.fileID != localList.fileID && serverList.creationTime >= localList.creationTime) {
162+
localList = IDList(
163+
name = name,
164+
url = serverList.url,
165+
fileID = serverList.fileID,
166+
size = 0,
167+
creationTime = serverList.creationTime,
168+
)
169+
idLists[name] = localList
170+
}
171+
if (serverList.size <= localList.size) {
172+
continue
173+
}
156174

157-
// check if fileID has changed, and it is indeed a newer file. If so, reset the list
158-
if (serverList.fileID != localList.fileID && serverList.creationTime >= localList.creationTime) {
159-
localList = IDList(
160-
name = name,
161-
url = serverList.url,
162-
fileID = serverList.fileID,
163-
size = 0,
164-
creationTime = serverList.creationTime,
175+
tasks.add(
176+
statsigScope.launch {
177+
downloadIDList(localList)
178+
},
165179
)
166-
idLists[name] = localList
167-
}
168-
if (serverList.size <= localList.size) {
169-
continue
170180
}
171181

172-
tasks.add(
173-
statsigScope.launch {
174-
downloadIDList(localList)
175-
},
176-
)
177-
}
178-
179-
tasks.joinAll()
180-
diagnostics.markEnd(KeyType.GET_ID_LIST_SOURCES, true, StepType.PROCESS)
182+
tasks.joinAll()
183+
diagnostics.markEnd(KeyType.GET_ID_LIST_SOURCES, true, StepType.PROCESS)
181184

182-
// remove deleted id lists
183-
val deletedLists = mutableListOf<String>()
184-
for (name in idLists.keys) {
185-
if (!jsonResponse.containsKey(name)) {
186-
deletedLists.add(name)
185+
// remove deleted id lists
186+
val deletedLists = mutableListOf<String>()
187+
for (name in idLists.keys) {
188+
if (!jsonResponse.containsKey(name)) {
189+
deletedLists.add(name)
190+
}
187191
}
188-
}
189-
for (name in deletedLists) {
190-
idLists.remove(name)
192+
for (name in deletedLists) {
193+
idLists.remove(name)
194+
}
195+
} catch (e: Exception) {
196+
throw e
197+
} finally {
198+
response?.close()
191199
}
192200
}
193201

194202
private suspend fun downloadIDList(list: IDList) {
195203
if (list.url == null) {
196204
return
197205
}
198-
206+
var response: Response? = null
199207
try {
200208
diagnostics.markStart(KeyType.GET_ID_LIST, StepType.NETWORK_REQUEST, additionalMarker = Marker(url = list.url))
201-
val response = network.getExternal(list.url, mapOf("Range" to "bytes=${list.size}-"))
209+
response = network.getExternal(list.url, mapOf("Range" to "bytes=${list.size}-"))
202210
diagnostics.markEnd(KeyType.GET_ID_LIST, response?.isSuccessful === true, StepType.NETWORK_REQUEST, additionalMarker = Marker(url = list.url, statusCode = response?.code, sdkRegion = response?.headers?.get("x-statsig-region")))
203211

204212
if (response?.isSuccessful !== true) {
@@ -234,6 +242,8 @@ internal class SpecStore constructor(
234242
errorBoundary.logException("downloadIDList", e)
235243
println("[Statsig]: An exception was caught: $e")
236244
diagnostics.markEnd(KeyType.GET_ID_LIST, false, StepType.NETWORK_REQUEST, additionalMarker = Marker(url = list.url))
245+
} finally {
246+
response?.close()
237247
}
238248
}
239249

@@ -424,16 +434,19 @@ internal class SpecStore constructor(
424434
}
425435

426436
suspend fun downloadConfigSpecs(): APIDownloadedConfigs? {
437+
var response: Response? = null
427438
try {
428-
val specs = this.network.downloadConfigSpecs(this.lastUpdateTime, this.options.initTimeoutMs) ?: return null
429-
val configs = gson.fromJson(specs.body?.charStream(), APIDownloadedConfigs::class.java)
439+
response = this.network.downloadConfigSpecs(this.lastUpdateTime, this.options.initTimeoutMs) ?: return null
440+
val configs = gson.fromJson(response.body?.charStream(), APIDownloadedConfigs::class.java)
430441
if (configs.hasUpdates) {
431442
this.lastUpdateTime = configs.time
432443
}
433444
return configs
434445
} catch (e: Exception) {
435446
errorBoundary.logException("downloadConfigSpecs", e)
436447
println("[Statsig]: An exception was caught: $e")
448+
} finally {
449+
response?.close()
437450
}
438451
return null
439452
}

src/main/kotlin/com/statsig/sdk/StatsigNetwork.kt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -171,19 +171,20 @@ internal class StatsigNetwork(
171171
): Response? {
172172
return request(
173173
statsigHttpClient.newBuilder().callTimeout(
174-
timeoutMs, TimeUnit.MILLISECONDS
174+
timeoutMs,
175+
TimeUnit.MILLISECONDS,
175176
).build(),
176177
url,
177178
null,
178-
headers
179+
headers,
179180
)
180181
}
181182

182183
suspend fun downloadConfigSpecs(sinceTime: Long, timeoutMs: Long): Response? {
183184
return get(
184185
"$apiForDownloadConfigSpecs/download_config_specs/$sdkKey.json?sinceTime=$sinceTime",
185186
emptyMap(),
186-
timeoutMs
187+
timeoutMs,
187188
)
188189
}
189190

0 commit comments

Comments
 (0)