Skip to content

Commit 8636bc8

Browse files
Merge pull request #89 from OneBusAway/release-please--branches--main--changes--next
release: 0.1.0-alpha.33
2 parents a1e74ac + 817df23 commit 8636bc8

7 files changed

Lines changed: 114 additions & 11 deletions

File tree

.release-please-manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
".": "0.1.0-alpha.32"
2+
".": "0.1.0-alpha.33"
33
}

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
# Changelog
22

3+
## 0.1.0-alpha.33 (2025-07-30)
4+
5+
Full Changelog: [v0.1.0-alpha.32...v0.1.0-alpha.33](https://github.com/OneBusAway/java-sdk/compare/v0.1.0-alpha.32...v0.1.0-alpha.33)
6+
7+
### Features
8+
9+
* add retryable exception ([f679fac](https://github.com/OneBusAway/java-sdk/commit/f679fac35bb7b6695d80dc3819f7d6ec884e9cc8))
10+
311
## 0.1.0-alpha.32 (2025-07-29)
412

513
Full Changelog: [v0.1.0-alpha.31...v0.1.0-alpha.32](https://github.com/OneBusAway/java-sdk/compare/v0.1.0-alpha.31...v0.1.0-alpha.32)

README.md

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22

33
<!-- x-release-please-start-version -->
44

5-
[![Maven Central](https://img.shields.io/maven-central/v/org.onebusaway/onebusaway-sdk-java)](https://central.sonatype.com/artifact/org.onebusaway/onebusaway-sdk-java/0.1.0-alpha.32)
6-
[![javadoc](https://javadoc.io/badge2/org.onebusaway/onebusaway-sdk-java/0.1.0-alpha.32/javadoc.svg)](https://javadoc.io/doc/org.onebusaway/onebusaway-sdk-java/0.1.0-alpha.32)
5+
[![Maven Central](https://img.shields.io/maven-central/v/org.onebusaway/onebusaway-sdk-java)](https://central.sonatype.com/artifact/org.onebusaway/onebusaway-sdk-java/0.1.0-alpha.33)
6+
[![javadoc](https://javadoc.io/badge2/org.onebusaway/onebusaway-sdk-java/0.1.0-alpha.33/javadoc.svg)](https://javadoc.io/doc/org.onebusaway/onebusaway-sdk-java/0.1.0-alpha.33)
77

88
<!-- x-release-please-end -->
99

@@ -15,7 +15,7 @@ It is generated with [Stainless](https://www.stainless.com/).
1515

1616
<!-- x-release-please-start-version -->
1717

18-
The REST API documentation can be found on [developer.onebusaway.org](https://developer.onebusaway.org). Javadocs are available on [javadoc.io](https://javadoc.io/doc/org.onebusaway/onebusaway-sdk-java/0.1.0-alpha.32).
18+
The REST API documentation can be found on [developer.onebusaway.org](https://developer.onebusaway.org). Javadocs are available on [javadoc.io](https://javadoc.io/doc/org.onebusaway/onebusaway-sdk-java/0.1.0-alpha.33).
1919

2020
<!-- x-release-please-end -->
2121

@@ -26,7 +26,7 @@ The REST API documentation can be found on [developer.onebusaway.org](https://de
2626
### Gradle
2727

2828
```kotlin
29-
implementation("org.onebusaway:onebusaway-sdk-java:0.1.0-alpha.32")
29+
implementation("org.onebusaway:onebusaway-sdk-java:0.1.0-alpha.33")
3030
```
3131

3232
### Maven
@@ -35,7 +35,7 @@ implementation("org.onebusaway:onebusaway-sdk-java:0.1.0-alpha.32")
3535
<dependency>
3636
<groupId>org.onebusaway</groupId>
3737
<artifactId>onebusaway-sdk-java</artifactId>
38-
<version>0.1.0-alpha.32</version>
38+
<version>0.1.0-alpha.33</version>
3939
</dependency>
4040
```
4141

@@ -221,6 +221,8 @@ The SDK throws custom unchecked exception types:
221221

222222
- [`OnebusawaySdkIoException`](onebusaway-sdk-java-core/src/main/kotlin/org/onebusaway/errors/OnebusawaySdkIoException.kt): I/O networking errors.
223223

224+
- [`OnebusawaySdkRetryableException`](onebusaway-sdk-java-core/src/main/kotlin/org/onebusaway/errors/OnebusawaySdkRetryableException.kt): Generic error indicating a failure that could be retried by the client.
225+
224226
- [`OnebusawaySdkInvalidDataException`](onebusaway-sdk-java-core/src/main/kotlin/org/onebusaway/errors/OnebusawaySdkInvalidDataException.kt): Failure to interpret successfully parsed data. For example, when accessing a property that's supposed to be required, but the API unexpectedly omitted it from the response.
225227

226228
- [`OnebusawaySdkException`](onebusaway-sdk-java-core/src/main/kotlin/org/onebusaway/errors/OnebusawaySdkException.kt): Base class for all exceptions. Most errors will result in one of the previously mentioned ones, but completely generic errors may be thrown using the base class.

build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ repositories {
88

99
allprojects {
1010
group = "org.onebusaway"
11-
version = "0.1.0-alpha.32" // x-release-please-version
11+
version = "0.1.0-alpha.33" // x-release-please-version
1212
}
1313

1414
subprojects {

onebusaway-sdk-java-core/src/main/kotlin/org/onebusaway/core/http/RetryingHttpClient.kt

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import kotlin.math.pow
1919
import org.onebusaway.core.RequestOptions
2020
import org.onebusaway.core.checkRequired
2121
import org.onebusaway.errors.OnebusawaySdkIoException
22+
import org.onebusaway.errors.OnebusawaySdkRetryableException
2223

2324
class RetryingHttpClient
2425
private constructor(
@@ -176,10 +177,10 @@ private constructor(
176177
}
177178

178179
private fun shouldRetry(throwable: Throwable): Boolean =
179-
// Only retry IOException and OnebusawaySdkIoException, other exceptions are not intended to
180-
// be
181-
// retried.
182-
throwable is IOException || throwable is OnebusawaySdkIoException
180+
// Only retry known retryable exceptions, other exceptions are not intended to be retried.
181+
throwable is IOException ||
182+
throwable is OnebusawaySdkIoException ||
183+
throwable is OnebusawaySdkRetryableException
183184

184185
private fun getRetryBackoffDuration(retries: Int, response: HttpResponse?): Duration {
185186
// About the Retry-After header:
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package org.onebusaway.errors
2+
3+
/**
4+
* Exception that indicates a transient error that can be retried.
5+
*
6+
* When this exception is thrown during an HTTP request, the SDK will automatically retry the
7+
* request up to the maximum number of retries.
8+
*
9+
* @param message A descriptive error message
10+
* @param cause The underlying cause of this exception, if any
11+
*/
12+
class OnebusawaySdkRetryableException
13+
@JvmOverloads
14+
constructor(message: String? = null, cause: Throwable? = null) :
15+
OnebusawaySdkException(message, cause)

onebusaway-sdk-java-core/src/test/kotlin/org/onebusaway/core/http/RetryingHttpClientTest.kt

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import org.junit.jupiter.params.ParameterizedTest
1414
import org.junit.jupiter.params.provider.ValueSource
1515
import org.onebusaway.client.okhttp.OkHttpClient
1616
import org.onebusaway.core.RequestOptions
17+
import org.onebusaway.errors.OnebusawaySdkRetryableException
1718

1819
@WireMockTest
1920
@ResourceLock("https://github.com/wiremock/wiremock/issues/169")
@@ -251,6 +252,82 @@ internal class RetryingHttpClientTest {
251252
assertNoResponseLeaks()
252253
}
253254

255+
@ParameterizedTest
256+
@ValueSource(booleans = [false, true])
257+
fun execute_withRetryableException(async: Boolean) {
258+
stubFor(post(urlPathEqualTo("/something")).willReturn(ok()))
259+
260+
var callCount = 0
261+
val failingHttpClient =
262+
object : HttpClient {
263+
override fun execute(
264+
request: HttpRequest,
265+
requestOptions: RequestOptions,
266+
): HttpResponse {
267+
callCount++
268+
if (callCount == 1) {
269+
throw OnebusawaySdkRetryableException("Simulated retryable failure")
270+
}
271+
return httpClient.execute(request, requestOptions)
272+
}
273+
274+
override fun executeAsync(
275+
request: HttpRequest,
276+
requestOptions: RequestOptions,
277+
): CompletableFuture<HttpResponse> {
278+
callCount++
279+
if (callCount == 1) {
280+
val future = CompletableFuture<HttpResponse>()
281+
future.completeExceptionally(
282+
OnebusawaySdkRetryableException("Simulated retryable failure")
283+
)
284+
return future
285+
}
286+
return httpClient.executeAsync(request, requestOptions)
287+
}
288+
289+
override fun close() = httpClient.close()
290+
}
291+
292+
val retryingClient =
293+
RetryingHttpClient.builder()
294+
.httpClient(failingHttpClient)
295+
.maxRetries(2)
296+
.sleeper(
297+
object : RetryingHttpClient.Sleeper {
298+
299+
override fun sleep(duration: Duration) {}
300+
301+
override fun sleepAsync(duration: Duration): CompletableFuture<Void> =
302+
CompletableFuture.completedFuture(null)
303+
}
304+
)
305+
.build()
306+
307+
val response =
308+
retryingClient.execute(
309+
HttpRequest.builder()
310+
.method(HttpMethod.POST)
311+
.baseUrl(baseUrl)
312+
.addPathSegment("something")
313+
.build(),
314+
async,
315+
)
316+
317+
assertThat(response.statusCode()).isEqualTo(200)
318+
verify(
319+
1,
320+
postRequestedFor(urlPathEqualTo("/something"))
321+
.withHeader("x-stainless-retry-count", equalTo("1")),
322+
)
323+
verify(
324+
0,
325+
postRequestedFor(urlPathEqualTo("/something"))
326+
.withHeader("x-stainless-retry-count", equalTo("0")),
327+
)
328+
assertNoResponseLeaks()
329+
}
330+
254331
private fun retryingHttpClientBuilder() =
255332
RetryingHttpClient.builder()
256333
.httpClient(httpClient)

0 commit comments

Comments
 (0)