Skip to content

Commit c1c6b55

Browse files
Do not use coroutines in jooq's transacter
This removes the use of `runBlocking` from the implementation, which will make it safer to invoke in async contexts GitOrigin-RevId: a43454271411160d866893df831f39a87e3eb26b
1 parent 4d7c5e5 commit c1c6b55

File tree

2 files changed

+22
-30
lines changed

2 files changed

+22
-30
lines changed

misk-jooq/build.gradle.kts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,7 @@ dependencies {
1919
api(project(":misk-inject"))
2020
api(project(":misk-jdbc"))
2121
implementation(libs.jakartaInject)
22-
implementation(libs.kotlinRetry)
23-
implementation(libs.kotlinxCoroutinesCore)
22+
implementation(project(":misk-backoff"))
2423
implementation(project(":wisp:wisp-logging"))
2524

2625
testImplementation(libs.assertj)

misk-jooq/src/main/kotlin/misk/jooq/JooqTransacter.kt

Lines changed: 21 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,6 @@
11
package misk.jooq
22

3-
import com.github.michaelbull.retry.ContinueRetrying
4-
import com.github.michaelbull.retry.StopRetrying
5-
import com.github.michaelbull.retry.context.retryStatus
6-
import com.github.michaelbull.retry.policy.RetryPolicy
7-
import com.github.michaelbull.retry.policy.fullJitterBackoff
8-
import com.github.michaelbull.retry.policy.limitAttempts
9-
import com.github.michaelbull.retry.policy.plus
10-
import com.github.michaelbull.retry.retry
11-
import kotlinx.coroutines.runBlocking
3+
import misk.backoff.ExponentialBackoff
124
import misk.jdbc.DataSourceConfig
135
import misk.jdbc.DataSourceService
146
import misk.jdbc.DataSourceType
@@ -29,7 +21,7 @@ import org.jooq.impl.DefaultExecuteListenerProvider
2921
import org.jooq.impl.DefaultTransactionProvider
3022
import wisp.logging.getLogger
3123
import java.time.Clock
32-
import kotlin.coroutines.coroutineContext
24+
import java.time.Duration
3325

3426
class JooqTransacter @JvmOverloads constructor(
3527
private val dataSourceService: DataSourceService,
@@ -46,34 +38,39 @@ class JooqTransacter @JvmOverloads constructor(
4638
options: TransacterOptions = TransacterOptions(),
4739
callback: (jooqSession: JooqSession) -> RETURN_TYPE
4840
): RETURN_TYPE {
49-
return runBlocking {
50-
retry(
51-
retryJooqExceptionsAlone +
52-
limitAttempts(options.maxAttempts) +
53-
fullJitterBackoff(base = 10L, max = options.maxRetryDelayMillis)
54-
) {
55-
performInTransaction(options, callback)
41+
val backoff = ExponentialBackoff(Duration.ofMillis(10L), Duration.ofMillis(options.maxRetryDelayMillis))
42+
var attempt = 0
43+
44+
while (true) {
45+
try {
46+
return performInTransaction(options, callback, ++attempt)
47+
} catch (e: Exception) {
48+
if (e !is DataAccessException || attempt >= options.maxAttempts) throw e
49+
val sleepDuration = backoff.nextRetry()
50+
if (!sleepDuration.isZero) {
51+
Thread.sleep(sleepDuration.toMillis())
52+
}
5653
}
5754
}
5855
}
5956

60-
private suspend fun <RETURN_TYPE> performInTransaction(
57+
private fun <RETURN_TYPE> performInTransaction(
6158
options: TransacterOptions,
62-
callback: (jooqSession: JooqSession) -> RETURN_TYPE
59+
callback: (jooqSession: JooqSession) -> RETURN_TYPE,
60+
attempt: Int,
6361
): RETURN_TYPE {
64-
val attempt1Based = coroutineContext.retryStatus.attempt + 1
6562
return try {
6663
val result = createDSLContextAndCallback(options, callback)
67-
if (attempt1Based > 1) {
64+
if (attempt > 1) {
6865
log.info {
69-
"Retried jooq transaction succeeded after [attempts=$attempt1Based]"
66+
"Retried jooq transaction succeeded after [attempts=$attempt]"
7067
}
7168
}
7269
result
7370
} catch (e: Exception) {
74-
if (attempt1Based >= options.maxAttempts) {
71+
if (attempt >= options.maxAttempts) {
7572
log.warn(e) {
76-
"Recoverable transaction exception [attempts=$attempt1Based], no more attempts"
73+
"Recoverable transaction exception [attempts=$attempt], no more attempts"
7774
}
7875
throw e
7976
}
@@ -167,10 +164,6 @@ class JooqTransacter @JvmOverloads constructor(
167164
companion object {
168165
private val log = getLogger<JooqTransacter>()
169166

170-
private val retryJooqExceptionsAlone: RetryPolicy<Throwable> = {
171-
if (reason is DataAccessException) ContinueRetrying else StopRetrying
172-
}
173-
174167
val noRetriesOptions: TransacterOptions
175168
get() = TransacterOptions().copy(maxAttempts = 1)
176169
}

0 commit comments

Comments
 (0)