Skip to content

Commit fd48d71

Browse files
authored
Merge pull request #400 from wafflestudio/develop
Release
2 parents ce8733d + 1a2684f commit fd48d71

File tree

2 files changed

+71
-36
lines changed

2 files changed

+71
-36
lines changed
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package com.wafflestudio.snutt.common.util
2+
3+
import kotlinx.coroutines.CoroutineDispatcher
4+
import kotlinx.coroutines.CoroutineScope
5+
import kotlinx.coroutines.Dispatchers
6+
import kotlinx.coroutines.SupervisorJob
7+
import kotlinx.coroutines.asCoroutineDispatcher
8+
import kotlinx.coroutines.delay
9+
import java.util.concurrent.Executors
10+
11+
object CoroutineUtils {
12+
val Dispatchers.Loom: CoroutineDispatcher
13+
get() = Executors.newVirtualThreadPerTaskExecutor().asCoroutineDispatcher()
14+
val applicationScope = CoroutineScope(SupervisorJob() + Dispatchers.Loom)
15+
16+
suspend fun <T> retryWithExponentialBackoff(
17+
retries: Int = 10,
18+
initialDelay: Long = 1000L,
19+
factor: Long = 2L,
20+
block: suspend () -> T,
21+
): T {
22+
var currentDelay = initialDelay
23+
for (i in 1..retries) {
24+
try {
25+
return block()
26+
} catch (e: Exception) {
27+
if (i == retries) {
28+
throw e
29+
}
30+
delay(currentDelay)
31+
currentDelay *= factor
32+
}
33+
}
34+
throw IllegalStateException("Can't reach here")
35+
}
36+
}

core/src/main/kotlin/notification/service/DeviceService.kt

Lines changed: 35 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ import com.wafflestudio.snutt.common.cache.Cache
44
import com.wafflestudio.snutt.common.cache.CacheKey
55
import com.wafflestudio.snutt.common.client.ClientInfo
66
import com.wafflestudio.snutt.common.push.PushClient
7+
import com.wafflestudio.snutt.common.util.CoroutineUtils
78
import com.wafflestudio.snutt.notification.data.UserDevice
89
import com.wafflestudio.snutt.notification.repository.UserDeviceRepository
910
import com.wafflestudio.snutt.users.repository.UserRepository
10-
import kotlinx.coroutines.coroutineScope
1111
import kotlinx.coroutines.launch
1212
import org.springframework.stereotype.Service
1313
import java.time.LocalDateTime
@@ -27,39 +27,39 @@ class DeviceService internal constructor(
2727
val cacheKey = CacheKey.LOCK_ADD_FCM_REGISTRATION_ID.build(userId, registrationId)
2828
if (!cache.acquireLock(cacheKey)) return
2929

30-
coroutineScope {
31-
launch {
30+
CoroutineUtils.applicationScope.launch {
31+
CoroutineUtils.retryWithExponentialBackoff {
3232
pushClient.subscribeGlobalTopic(registrationId)
3333
}
34+
}
3435

35-
launch {
36-
val userDevice =
37-
clientInfo.deviceId?.let {
38-
userDeviceRepository.findByUserIdAndDeviceIdAndIsDeletedFalse(userId, it)
39-
} ?: userDeviceRepository.findByUserIdAndFcmRegistrationIdAndIsDeletedFalse(userId, registrationId)
36+
try {
37+
val userDevice =
38+
clientInfo.deviceId?.let {
39+
userDeviceRepository.findByUserIdAndDeviceIdAndIsDeletedFalse(userId, it)
40+
} ?: userDeviceRepository.findByUserIdAndFcmRegistrationIdAndIsDeletedFalse(userId, registrationId)
4041

41-
userDevice?.apply {
42-
if (updateIfChanged(clientInfo, registrationId)) {
43-
userDeviceRepository.save(this)
44-
}
45-
} ?: run {
46-
userDeviceRepository.save(
47-
UserDevice(
48-
userId = userId,
49-
osType = clientInfo.osType,
50-
osVersion = clientInfo.osVersion,
51-
deviceId = clientInfo.deviceId,
52-
deviceModel = clientInfo.deviceModel,
53-
appType = clientInfo.appType,
54-
appVersion = clientInfo.appVersion,
55-
fcmRegistrationId = registrationId,
56-
),
57-
)
42+
userDevice?.apply {
43+
if (updateIfChanged(clientInfo, registrationId)) {
44+
userDeviceRepository.save(this)
5845
}
46+
} ?: run {
47+
userDeviceRepository.save(
48+
UserDevice(
49+
userId = userId,
50+
osType = clientInfo.osType,
51+
osVersion = clientInfo.osVersion,
52+
deviceId = clientInfo.deviceId,
53+
deviceModel = clientInfo.deviceModel,
54+
appType = clientInfo.appType,
55+
appVersion = clientInfo.appVersion,
56+
fcmRegistrationId = registrationId,
57+
),
58+
)
5959
}
60+
} finally {
61+
cache.releaseLock(cacheKey)
6062
}
61-
62-
cache.releaseLock(cacheKey)
6363
}
6464

6565
private fun UserDevice.updateIfChanged(
@@ -90,17 +90,16 @@ class DeviceService internal constructor(
9090
suspend fun removeRegistrationId(
9191
userId: String,
9292
registrationId: String,
93-
) = coroutineScope {
94-
launch {
95-
pushClient.unsubscribeGlobalTopic(registrationId)
96-
}
97-
98-
launch {
99-
userDeviceRepository.findByUserIdAndFcmRegistrationIdAndIsDeletedFalse(userId, registrationId)?.let {
100-
it.isDeleted = true
101-
userDeviceRepository.save(it)
93+
) {
94+
CoroutineUtils.applicationScope.launch {
95+
CoroutineUtils.retryWithExponentialBackoff {
96+
pushClient.unsubscribeGlobalTopic(registrationId)
10297
}
10398
}
99+
userDeviceRepository.findByUserIdAndFcmRegistrationIdAndIsDeletedFalse(userId, registrationId)?.let {
100+
it.isDeleted = true
101+
userDeviceRepository.save(it)
102+
}
104103
}
105104

106105
suspend fun getUserDevices(userId: String): List<UserDevice> =

0 commit comments

Comments
 (0)