Skip to content

Commit 9ab1ea2

Browse files
committed
Handle completed futures on the list of outstanding bulkhead requests
1 parent fccedd8 commit 9ab1ea2

File tree

1 file changed

+23
-7
lines changed

1 file changed

+23
-7
lines changed

core/src/main/java/dev/failsafe/internal/BulkheadImpl.java

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -96,14 +96,30 @@ synchronized CompletableFuture<Void> acquirePermitAsync() {
9696

9797
@Override
9898
public synchronized void releasePermit() {
99-
if (permits < maxPermits) {
100-
permits += 1;
101-
CompletableFuture<Void> future = futures.pollFirst();
102-
if (future != null){
103-
permits -= 1;
104-
future.complete(null);
99+
if (permits < maxPermits) {
100+
permits += 1;
101+
/*
102+
* It is possible to get future from the list that already had been completed. This
103+
* happens because setting future to 'completed' state happens before (and not
104+
* atomically with) removing future from the list. Handle this by pulling futures from
105+
* the list until we find one we can complete (or reach the end of the list). Not doing
106+
* this may result in 'dandling' messages in the list that are never completed. For some
107+
* details see FutureLinkedList.add - how it returns a future that weill remove entry
108+
* from the list when it is completed. And also see BulkheadExecutor.preExecuteAsync
109+
* that calls acquirePermitAsync and gets that future in response.
110+
*/
111+
while (true) {
112+
CompletableFuture<Void> future = futures.pollFirst();
113+
if (future == null) {
114+
break;
115+
}
116+
permits -= 1;
117+
if (future.complete(null)) {
118+
break;
119+
}
120+
permits += 1;
121+
}
105122
}
106-
}
107123
}
108124

109125
@Override

0 commit comments

Comments
 (0)