-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Improves the retry behavior of functions (#39)
* Rename clashing function with getConfig getter * Add Retriable and NonRetriable exceptions * Return retry headers with error responses * Add tests for retriable/non-retriable function errors * Rename enum BadRequest -> NonRetriableError * Rename enum Error -> RetriableError
- Loading branch information
Showing
10 changed files
with
212 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
5 changes: 5 additions & 0 deletions
5
inngest-core/src/main/kotlin/com/inngest/NonRetriableError.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
package com.inngest | ||
|
||
open class NonRetriableError | ||
@JvmOverloads | ||
constructor(message: String, cause: Throwable? = null) : RuntimeException(message, cause) |
21 changes: 21 additions & 0 deletions
21
inngest-core/src/main/kotlin/com/inngest/RetryAfterError.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package com.inngest | ||
|
||
import java.time.ZonedDateTime | ||
import java.time.format.DateTimeFormatter | ||
|
||
open class RetryAfterError | ||
@JvmOverloads | ||
constructor(message: String, retryAfter: Any, cause: Throwable? = null) : | ||
RuntimeException(message, cause) { | ||
var retryAfter: String = | ||
when (retryAfter) { | ||
is ZonedDateTime -> retryAfter.format(DateTimeFormatter.ISO_INSTANT) | ||
|
||
is Int -> (retryAfter / 1000).toString() | ||
|
||
// TODO: Add ms parsing: https://github.com/vercel/ms | ||
is String -> (retryAfter.toInt() / 1000).toString() | ||
|
||
else -> throw IllegalArgumentException("Invalid retryAfter type: ${retryAfter::class.simpleName}") | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package com.inngest | ||
|
||
internal data class RetryDecision(val shouldRetry: Boolean, val headers: Map<String, String>) { | ||
companion object { | ||
internal fun fromException(exception: Exception): RetryDecision = | ||
when (exception) { | ||
is RetryAfterError -> | ||
RetryDecision( | ||
true, | ||
mapOf(InngestHeaderKey.RetryAfter.value to exception.retryAfter, noRetryFalse), | ||
) | ||
|
||
is NonRetriableError -> RetryDecision(false, mapOf(InngestHeaderKey.NoRetry.value to "true")) | ||
|
||
// Any other error should have the default retry behavior. | ||
else -> RetryDecision(true, mapOf(noRetryFalse)) | ||
} | ||
} | ||
} | ||
|
||
private val noRetryFalse = InngestHeaderKey.NoRetry.value to "false" |
28 changes: 28 additions & 0 deletions
28
inngest-core/src/test/kotlin/com/inngest/RetryAfterErrorTest.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package com.inngest | ||
|
||
import java.time.ZonedDateTime | ||
import kotlin.test.Test | ||
import kotlin.test.assertEquals | ||
|
||
internal class RetryAfterErrorTest { | ||
@Test | ||
fun `should return retryAfter in seconds when an integer is passed`() { | ||
val retryAfter = 5000 | ||
val retryAfterError = RetryAfterError("Error", retryAfter) | ||
assertEquals("5", retryAfterError.retryAfter) | ||
} | ||
|
||
@Test | ||
fun `should return retryAfter in seconds when an string is passed`() { | ||
val retryAfter = "5000" | ||
val retryAfterError = RetryAfterError("Error", retryAfter) | ||
assertEquals("5", retryAfterError.retryAfter) | ||
} | ||
|
||
@Test | ||
fun `should return retryAfter as an ISO string when a ZonedDateTime is passed`() { | ||
val retryAfter = ZonedDateTime.parse("2021-08-25T00:00:00Z") | ||
val retryAfterError = RetryAfterError("Error", retryAfter) | ||
assertEquals("2021-08-25T00:00:00Z", retryAfterError.retryAfter) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
71 changes: 71 additions & 0 deletions
71
...ring-boot-demo/src/test/java/com/inngest/springbootdemo/ErrorsInStepsIntegrationTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
package com.inngest.springbootdemo; | ||
|
||
import com.inngest.CommHandler; | ||
import com.inngest.Inngest; | ||
import org.junit.jupiter.api.BeforeAll; | ||
import org.junit.jupiter.api.Test; | ||
import org.junit.jupiter.api.parallel.Execution; | ||
import org.junit.jupiter.api.parallel.ExecutionMode; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
|
||
import java.util.ArrayList; | ||
import java.util.LinkedHashMap; | ||
|
||
import static org.junit.jupiter.api.Assertions.assertEquals; | ||
import static org.junit.jupiter.api.Assertions.assertNotNull; | ||
|
||
@IntegrationTest | ||
@Execution(ExecutionMode.CONCURRENT) | ||
class ErrorsInStepsIntegrationTest { | ||
@BeforeAll | ||
static void setup(@Autowired CommHandler handler) { | ||
handler.register(); | ||
} | ||
|
||
@Autowired | ||
private DevServerComponent devServer; | ||
|
||
static int sleepTime = 10000; | ||
|
||
@Autowired | ||
private Inngest client; | ||
|
||
@Test | ||
void testNonRetriableShouldFail() throws Exception { | ||
String eventId = InngestFunctionTestHelpers.sendEvent(client, "test/non.retriable").first(); | ||
|
||
Thread.sleep(sleepTime); | ||
|
||
RunEntry<Object> run = devServer.runsByEvent(eventId).first(); | ||
LinkedHashMap<String, String> output = (LinkedHashMap<String, String>) run.getOutput(); | ||
|
||
assertEquals(run.getStatus(), "Failed"); | ||
assertNotNull(run.getEnded_at()); | ||
assert output.get("name").contains("NonRetriableError"); | ||
assert output.get("stack").contains("lambda$nonRetriableErrorFunction"); | ||
assertEquals(output.get("message"), "something fatally went wrong"); | ||
} | ||
|
||
|
||
@Test | ||
void testRetriableShouldSucceedAfterFirstAttempt() throws Exception { | ||
String eventId = InngestFunctionTestHelpers.sendEvent(client, "test/retriable").first(); | ||
|
||
Thread.sleep(5000); | ||
|
||
RunEntry<Object> run1 = devServer.runsByEvent(eventId).first(); | ||
|
||
assertEquals(run1.getStatus(), "Running"); | ||
|
||
// The second attempt should succeed, so we wait for the second run to finish. | ||
Thread.sleep(15000); | ||
|
||
RunEntry<Object> run2 = devServer.runsByEvent(eventId).first(); | ||
|
||
assertEquals(run2.getStatus(), "Completed"); | ||
assertNotNull(run2.getEnded_at(), "Completed"); | ||
assertNotNull(run2.getOutput(), "Success"); | ||
} | ||
|
||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters