From c18465be2198ad69be53071f6cdc8127187f7874 Mon Sep 17 00:00:00 2001 From: Nikolai Obedin Date: Wed, 14 Aug 2024 18:22:05 +0200 Subject: [PATCH] Make repository functions suspending Add `suspend` modifier to the functions in `IdempotentResponseRepository` interface. The change enables usage of async clients (e.g. [kreds][1] or jooq-r2dbc) in repository implementation without `runBlocking` while requiring almost no changes to existing blocking implementations. [1]: https://github.com/crackthecodeabhi/kreds --- .github/workflows/pre-merge.yml | 5 +---- .../ktor/idempotency/IdempotentResponseRepository.kt | 6 +++--- src/test/kotlin/IdempotencyPluginTests.kt | 9 +++++---- src/test/kotlin/InMemoryResponseRepository.kt | 6 +++--- 4 files changed, 12 insertions(+), 14 deletions(-) diff --git a/.github/workflows/pre-merge.yml b/.github/workflows/pre-merge.yml index 85d8367..5892231 100644 --- a/.github/workflows/pre-merge.yml +++ b/.github/workflows/pre-merge.yml @@ -26,9 +26,6 @@ jobs: - name: Checkout Repo uses: actions/checkout@v2 - name: Check that the publish plugin works - env: - ORG_GRADLE_PROJECT_signingKey: ${{ secrets.ORG_GRADLE_PROJECT_SIGNINGKEY }} - ORG_GRADLE_PROJECT_signingPassword: ${{ secrets.ORG_GRADLE_PROJECT_SIGNINGPASSWORD }} uses: gradle/gradle-build-action@v2 with: arguments: publishToMavenLocal @@ -41,4 +38,4 @@ jobs: - name: Check that the code is formatted uses: gradle/gradle-build-action@v2 with: - arguments: spotlessCheck \ No newline at end of file + arguments: spotlessCheck diff --git a/src/main/kotlin/com/wolt/utils/ktor/idempotency/IdempotentResponseRepository.kt b/src/main/kotlin/com/wolt/utils/ktor/idempotency/IdempotentResponseRepository.kt index 0b9a45b..29fc9f2 100644 --- a/src/main/kotlin/com/wolt/utils/ktor/idempotency/IdempotentResponseRepository.kt +++ b/src/main/kotlin/com/wolt/utils/ktor/idempotency/IdempotentResponseRepository.kt @@ -5,18 +5,18 @@ import kotlinx.serialization.Serializable import java.time.OffsetDateTime interface IdempotentResponseRepository { - fun storeResponse( + suspend fun storeResponse( resource: String, idempotencyKey: IdempotencyKey, response: ByteArray, ) - fun getResponseOrLock( + suspend fun getResponseOrLock( resource: String, idempotencyKey: IdempotencyKey, ): IdempotencyResponse? - fun deleteExpiredResponses(lastValidDate: OffsetDateTime) + suspend fun deleteExpiredResponses(lastValidDate: OffsetDateTime) } data class IdempotencyResponse( diff --git a/src/test/kotlin/IdempotencyPluginTests.kt b/src/test/kotlin/IdempotencyPluginTests.kt index 2e77cd0..f2da97b 100644 --- a/src/test/kotlin/IdempotencyPluginTests.kt +++ b/src/test/kotlin/IdempotencyPluginTests.kt @@ -32,6 +32,7 @@ import io.ktor.server.routing.post import io.ktor.server.routing.put import io.ktor.server.testing.ApplicationTestBuilder import io.ktor.server.testing.testApplication +import io.mockk.coVerify import io.mockk.mockk import io.mockk.spyk import io.mockk.verify @@ -272,13 +273,13 @@ class IdempotencyPluginTests { val response = sendPostRequest(path, idempotencyKey) assertOkResponse(response, "Hello, world!") assertServiceCalled(timesInTotal = 1) - verify(exactly = 1) { repository.storeResponse("POST $path", any(), any()) } + coVerify(exactly = 1) { repository.storeResponse("POST $path", any(), any()) } val response2 = sendPostRequest(path, idempotencyKey) assertOkResponse(response2, "Hello, world!") assertServiceCalled(timesInTotal = 1) // storeResponse should not be called again - verify(exactly = 1) { repository.storeResponse("POST $path", any(), any()) } + coVerify(exactly = 1) { repository.storeResponse("POST $path", any(), any()) } } @Test @@ -323,7 +324,7 @@ class IdempotencyPluginTests { assertOkResponse(response1, "Hello, world for get request!") assertOkResponse(response2, "Hello, world for get request!") - verify(exactly = 0) { repository.storeResponse(any(), any(), any()) } + coVerify(exactly = 0) { repository.storeResponse(any(), any(), any()) } assertNoEventTriggered() assertServiceCalled(timesInTotal = 2) } @@ -373,7 +374,7 @@ class IdempotencyPluginTests { } } - private fun insertExpiredResponse( + private suspend fun insertExpiredResponse( idempotencyKey: String, path: String, method: HttpMethod = HttpMethod.Post, diff --git a/src/test/kotlin/InMemoryResponseRepository.kt b/src/test/kotlin/InMemoryResponseRepository.kt index 47b5717..833ca9d 100644 --- a/src/test/kotlin/InMemoryResponseRepository.kt +++ b/src/test/kotlin/InMemoryResponseRepository.kt @@ -8,7 +8,7 @@ import java.util.concurrent.ConcurrentHashMap class InMemoryResponseRepository : IdempotentResponseRepository { private val responses = ConcurrentHashMap() - override fun storeResponse( + override suspend fun storeResponse( resource: String, idempotencyKey: IdempotencyKey, response: ByteArray, @@ -17,7 +17,7 @@ class InMemoryResponseRepository : IdempotentResponseRepository { responses[generateKey(resource, idempotencyKey)] = IdempotencyResponse(isInProgress = false, response = response) } - override fun getResponseOrLock( + override suspend fun getResponseOrLock( resource: String, idempotencyKey: IdempotencyKey, ): IdempotencyResponse? { @@ -30,7 +30,7 @@ class InMemoryResponseRepository : IdempotentResponseRepository { return record } - override fun deleteExpiredResponses(lastValidDate: java.time.OffsetDateTime) { + override suspend fun deleteExpiredResponses(lastValidDate: java.time.OffsetDateTime) { responses.clear() }