Cache /api/stellar/liquidity lookups (#375) - #552
Open
Vyacheslav-Tomashevskiy wants to merge 1 commit into
Open
Conversation
Unlike Northgate-Systems#374's /api/stellar/rate (whose sibling rates.ts already had an in-memory cache), /api/stellar/liquidity had no caching anywhere - every request called server.liquidityPools().forAssets(asset).limit(1).order("desc").call() straight against Horizon, a real network round-trip, on every single call. - src/lib/stellar.ts: new getLiquidityPool(assetCode) wraps the existing lookup logic (moved out of the route handler) with a short-TTL (60s) in-memory cache keyed by uppercased asset code, matching the pattern already used for rates in src/lib/rates.ts. The "no issuer configured" / "no pool found" answers are cached too - they're a stable, real result (not a degraded fallback the way rates.ts's hardcoded rate is), so there's no reason to re-ask Horizon for an asset that will never have a pool. - src/app/api/stellar/liquidity/route.ts: now calls getLiquidityPool() instead of querying Horizon directly, and sets Cache-Control on every response - 'private, max-age=60, stale-while-revalidate=120' on a successful lookup (private, not public, since this route requires a session), 'no-store' on the 401/400/500 paths, which weren't setting any Cache-Control before either. - Added src/lib/__tests__/stellar-liquidity-cache.test.ts (6 tests, mocking @stellar/stellar-sdk's Horizon.Server so no real network calls happen): a fresh asset hits Horizon once, a second lookup for the same asset is served from cache without a second Horizon call, different asset codes cache independently, an asset with no configured issuer never touches Horizon at all, that 'no issuer' answer is cached too, and a genuinely empty pool result is reported with a reason. Each test imports a fresh copy of the module (vi.resetModules()) so the module-private cache Map starts empty every time - otherwise leftover cache state from an earlier test would make the 'does this actually skip Horizon' assertions pass for the wrong reason. - Added src/app/api/stellar/liquidity/__tests__/route.test.ts (6 tests, mocking @/lib/auth and @/lib/stellar): correct Cache-Control on a live and a cached lookup, a null-pool answer still gets cached (it's not a degraded value), unauthenticated/missing-param/error paths all get no-store and never call getLiquidityPool. Verified: temporarily restored the known missing isValidStellarPublicKey import (Northgate-Systems#529) to run this locally, since validations.ts (and therefore this route, transitively) won't load on main without it - reverted before this commit, git diff on validations.ts is empty. - New test files: 12/12 passing. Full suite: 76 passed (the pre-existing 64 plus these 12), same 2 pre-existing failures from a bad fixture address in validations.test.ts, unrelated to this change. - npm run dev + curl: unauthenticated and missing-param requests to the live route both return the expected status with Cache-Control: no-store, confirming the header logic runs on a real server. Couldn't drive the 200 path live in this sandbox (no real Supabase instance to back a session), so that path - and the actual caching behavior - is covered by the unit tests instead. - tsc --noEmit: no new errors (same pre-existing Northgate-Systems#529 and an unrelated transactions/[id] test type-mismatch present on main). - eslint: clean.
|
Someone is attempting to deploy a commit to the codex723's projects Team on Vercel. A member of the Team first needs to authorize it. |
6 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #375.
What was actually missing
Unlike #374's
/api/stellar/rate(whose siblingrates.tsalready had an in-memory cache, so that one just needed the HTTP layer),/api/stellar/liquidityhad no caching anywhere. Every single request calledserver.liquidityPools().forAssets(asset).limit(1).order("desc").call()straight against Horizon - a real network round-trip, every time.Change
src/lib/stellar.ts: newgetLiquidityPool(assetCode)moves the lookup logic out of the route handler and wraps it with a short-TTL (60s) in-memory cache keyed by uppercased asset code - same pattern already used for rates insrc/lib/rates.ts. The "no issuer configured" / "no pool found" answers get cached too: unlikerates.ts's hardcoded fallback rate (which is a degraded substitute for a live value and deliberately isn't cached that way), "this asset has no pool" is a stable, real answer that won't change until an issuer gets configured or a pool gets created - there's no reason to keep re-asking Horizon for it.src/app/api/stellar/liquidity/route.ts: now callsgetLiquidityPool()instead of querying Horizon directly, and setsCache-Controlon every response:private, max-age=60, stale-while-revalidate=120on a successful lookup -private(notpublic), since this route requires a session and a shared/CDN cache must never serve one user's authenticated response to a different, unauthenticated request.no-storeon the 401/400/500 paths, which weren't setting anyCache-Controlbefore either.Added
src/lib/__tests__/stellar-liquidity-cache.test.ts(6 tests, mocking@stellar/stellar-sdk'sHorizon.Serverso no real network calls happen): a fresh asset hits Horizon once, a second lookup for the same asset is served from cache without a second Horizon call, different asset codes cache independently, an asset with no configured issuer never touches Horizon at all, that "no issuer" answer is cached too, and a genuinely empty pool result is reported with a reason. Each test imports a fresh copy of the module (vi.resetModules()) so the module-private cache doesn't leak state between tests.Added
src/app/api/stellar/liquidity/__tests__/route.test.ts(6 tests, mocking@/lib/authand@/lib/stellar): correctCache-Controlon a live and a cached lookup, a null-pool answer still gets cached, and unauthenticated/missing-param/error paths all getno-storewithout ever callinggetLiquidityPool.Verification
isValidStellarPublicKeyimport (fix(validations): restore broken isValidStellarPublicKey import; feat: add /api/stellar/fee-estimate #529) to run this locally, sincevalidations.tswon't load onmainwithout it. New test files: 12/12 passing. Reverted before this commit (git diffonvalidations.tsis empty in this PR).validations.test.ts, unrelated to this change.npm run dev+curl: unauthenticated and missing-param requests to the live route both return the expected status withCache-Control: no-store, confirming the header logic runs on a real server. Couldn't drive the 200 path live in this sandbox (no real Supabase instance to back a session), so that path - and the actual caching behavior - is covered by the unit tests instead.tsc --noEmit- no new errors (same pre-existing fix(validations): restore broken isValidStellarPublicKey import; feat: add /api/stellar/fee-estimate #529 and an unrelatedtransactions/[id]test type-mismatch present onmain).eslint- clean./claim