| 1534 | private final Object marketsLock = new Object(); |
| 1535 | |
| 1536 | public java.util.concurrent.CompletableFuture<Object> loadMarkets(Object... args) { |
| 1537 | |
| 1538 | var reload = (Boolean) Helpers.getArg(args, 0, false); |
| 1539 | if (this.marketsLoaded && !reload) { |
| 1540 | return this.marketsLoading; |
| 1541 | } |
| 1542 | synchronized (marketsLock) { |
| 1543 | // Re-check under the lock to collapse concurrent first-callers onto the same future. |
| 1544 | if (this.marketsLoaded && !reload) { |
| 1545 | return this.marketsLoading; |
| 1546 | } |
| 1547 | // Collapse concurrent callers onto the same in-flight reload regardless |
| 1548 | // of the reload flag. The previous `|| reload` short-circuit caused 20 |
| 1549 | // concurrent loadMarkets(true) callers to spawn 20 sequential fetches. |
| 1550 | // The cache-vs-fetch decision still respects `reload` via the early |
| 1551 | // `marketsLoaded && !reload` guard above; this branch only decides |
| 1552 | // whether to start a *new* fetch when none is in-flight. |
| 1553 | if (!this.reloadingMarkets) { |
| 1554 | this.reloadingMarkets = true; |
| 1555 | try { |
| 1556 | this.marketsLoading = this.loadMarketsHelper(reload) |
| 1557 | .thenApply(res -> { |
| 1558 | synchronized (marketsLock) { |
| 1559 | this.reloadingMarkets = false; |
| 1560 | this.marketsLoaded = true; |
| 1561 | } |
| 1562 | return res; |
| 1563 | }) |
| 1564 | .exceptionallyCompose(ex -> { |
| 1565 | synchronized (marketsLock) { |
| 1566 | this.reloadingMarkets = false; |
| 1567 | this.marketsLoading = null; |
| 1568 | } |
| 1569 | return CompletableFuture.failedFuture(ex); |
| 1570 | }); |
| 1571 | } catch (ExecutionException | InterruptedException e) { |
| 1572 | this.reloadingMarkets = false; |
| 1573 | throw new RuntimeException(e); |
| 1574 | } |
| 1575 | } |
| 1576 | return this.marketsLoading; |
| 1577 | } |
| 1578 | } |
| 1579 | |
| 1580 | public CompletableFuture<Object> fetchCurrencies(Object... params) { |
| 1581 | return CompletableFuture.completedFuture(this.currencies); |