Skip to content

Replace the ducttape dependency with resilience4j - #2

Closed
austince wants to merge 1 commit into
mainfrom
replace-ducttape-resilience4j
Closed

Replace the ducttape dependency with resilience4j#2
austince wants to merge 1 commit into
mainfrom
replace-ducttape-resilience4j

Conversation

@austince

@austinceaustince commented May 19, 2026

Copy link
Copy Markdown
Owner

Fixestestcontainers#9227 by moving from duct-tape to resilience4j, as described in: testcontainers#9241 (comment)

I have added a wrapper interface to not expose the shaded resilience4j types and keep the ~same compile-time interface that ducttape exposed, hoping to reduce upgrade churn for the standard paths.

Removes the dependency on org.rnorth.duct-tape:duct-tape:1.0.8 by
re-implementing the small subset of duct-tape used by Testcontainers
inside org.testcontainers.utility, backed by resilience4j modules per
maintainer preference in testcontainers#9241.
New runtime dependencies (shaded):
- io.github.resilience4j:resilience4j-timelimiter:1.7.1
- io.github.resilience4j:resilience4j-ratelimiter:1.7.1
Internal package additions (org.testcontainers.utility):
- RateLimiter (interface) + RateLimiterBuilder: thin facade with the
historical duct-tape method names doWhenReady / getWhenReady, backed
by a resilience4j RateLimiter adapter. The shaded resilience4j type
never leaks into the public API.
- Timeouts.getWithTimeout / doWithTimeout: per-call ExecutorService
with daemon worker thread, shutdownNow() in finally and resilience4j
TimeLimiter (cancelRunningFuture=true) — fixes the duct-tape
zombie-thread bug (testcontainers#9227).
- Unreliables.retryUntilSuccess / retryUntilTrue: retry loop wrapped
in Timeouts.getWithTimeout. Interrupt-induced exceptions
(resilience4j's AcquirePermissionCancelledException, etc.) are not
allowed to overwrite the genuine last failure so callers diagnose
the real cause (e.g. SSLHandshakeException).
- TimeoutException, RetryCountExceededException: unchecked, matching
duct-tape's semantics so existing callers compile unchanged. Message
"Retry limit hit with exception" is preserved verbatim for
GenericContainerTest's existing assertion.
Public API impact:
- AbstractWaitStrategy.getRateLimiter() and withRateLimiter() now take
org.testcontainers.utility.RateLimiter instead of
org.rnorth.ducttape.ratelimits.RateLimiter. Source-compat is preserved
for callers that go through AbstractWaitStrategy; only callers that
explicitly imported the duct-tape types break.
- Both methods are added to japicmp's methodExcludes with a comment
explaining the binary-breaking change.
Callers updated to use the new types: GenericContainer,
HttpWaitStrategy, ShellStrategy, DockerHealthcheckWaitStrategy,
WaitAllStrategy, StartupCheckStrategy, DockerClientProviderStrategy,
RyukResourceReaper, CassandraQueryWaitStrategy (both packages),
YugabyteDBY{CQL,SQL}WaitStrategy, and the corresponding tests.
Refs: testcontainers#9241
@austince
austinceforce-pushed the replace-ducttape-resilience4j branch from 35de6f7 to 89e8bffCompareMay 19, 2026 21:42
@austince
austince marked this pull request as ready for review May 19, 2026 21:43
@austince

Copy link
Copy Markdown
OwnerAuthor

openning upstream

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: duct-tape:1.0.8 contains a Thread Leak

1 participant

@austince