11package 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
124import misk.jdbc.DataSourceConfig
135import misk.jdbc.DataSourceService
146import misk.jdbc.DataSourceType
@@ -29,7 +21,7 @@ import org.jooq.impl.DefaultExecuteListenerProvider
2921import org.jooq.impl.DefaultTransactionProvider
3022import wisp.logging.getLogger
3123import java.time.Clock
32- import kotlin.coroutines.coroutineContext
24+ import java.time.Duration
3325
3426class 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