Skip to content

Commit 8143c1e

Browse files
authored
General: Stop the shared resource churn tests flaking on a benign teardown race (#59)
The churn retry loops in SharedResourceTest read r.item on a resource freshly returned by get(). When gen-1 dies spontaneously, its async onCompletion cleanup force-closes every lease, including one that get() just handed out: the isClosed re-check inside get() and the caller's item read are not atomic. Resource.item then throws CancellationException("Resource was cancelled!"), failing the test. Observed in CI on the testGplay lane (run 32723097381, attempt 1) at SharedResourceTest.kt:918 with item value 1, i.e. a dead gen-1 reuse. Force-closing the leases of a spontaneously dead generation is designed behavior, so this is test tolerance, not a product fix: both churn loops now catch the throwing read and treat it as another dead-gen-1 reuse to retry. The supersede test's loop had the identical latent race.
1 parent 7348084 commit 8143c1e

1 file changed

Lines changed: 6 additions & 2 deletions

File tree

app-common/src/test/java/eu/darken/butler/common/sharedresource/SharedResourceTest.kt

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -835,7 +835,9 @@ class SharedResourceTest : BaseTest() {
835835
var r = sr.get()
836836
var guard = 0
837837
// A transient get() may reuse the not-yet-detached (dead) gen-1; retry until gen-2.
838-
while (r.item == 1 && guard++ < 1000) {
838+
// Gen-1's async self-teardown may force-close the freshly handed-out lease between
839+
// get() and the item read, making `item` throw — treat that as dead-gen-1 reuse too.
840+
while (runCatching { r.item }.getOrNull() != 2 && guard++ < 1000) {
839841
r.close()
840842
r = sr.get()
841843
}
@@ -915,7 +917,9 @@ class SharedResourceTest : BaseTest() {
915917
val r2 = withTimeout(5_000) {
916918
var r = sr.get()
917919
var guard = 0
918-
while (r.item == 1 && guard++ < 2000) {
920+
// Tolerate `item` throwing when gen-1's self-teardown force-closes a fresh lease
921+
// mid-read (see the sibling supersede test's churn loop).
922+
while (runCatching { r.item }.getOrNull() != 2 && guard++ < 2000) {
919923
r.close()
920924
r = sr.get()
921925
}

0 commit comments

Comments
 (0)