fix: Asset Issuer caching, e2e tests and metrics, Database Pooler stats caching (#1050, #1051, #1053, #1055) - #1580
Merged
emdevelopa merged 4 commits intoSep 25, 2026
Conversation
|
@matteorossi-codes Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
|
@matteorossi-codes is attempting to deploy a commit to the Emmanuel's projects Team on Vercel. A member of the Team first needs to authorize it. |
getIssuerStats and getAssetIssuerHealthMetrics re-queried the database on every call. Both are aggregate reads over payment rows that change slowly, so they now sit behind a bounded TTL cache (60s, 500 entries, LRU with oldest-first eviction), keyed per issuer and per merchant. Expired entries are dropped on read, failed reads are never cached, and logAssetIssuerVerification invalidates exactly the issuer and merchant keys a verification write can affect. invalidateQueryCache() with no arguments clears everything; a call that names neither key is a no-op, so a write with no known issuer cannot wipe the cache for other callers.
Adds tests/asset-issuer-e2e.test.js (18 tests) driving the module through its public entry points -- the AssetIssuerManager facade, the exported singleton and the rate-limit factory -- rather than the per-class unit tests already in src/lib/asset-issuer.test.js. Horizon, Postgres, Redis and the logger are mocked, so the suite needs no network or database. Covers the verification flow, on-chain issuer confirmation, merchant issuer configuration, verification logging, degradation and circuit-breaker recovery, dead-letter handling, and the module surface.
…lopa#1053) Adds nine Prometheus series and wires them into the module: verification counts and latency, query-cache hit/miss/eviction/invalidation counters and a size gauge, per-query duration, error-recovery outcomes, aggregated circuit-breaker state gauges, and a dead-letter queue size gauge. Per-issuer and per-transaction detail is deliberately not exported as label values. Issuers, merchants and transaction hashes are unbounded, so labelling by them would let a caller grow the series cardinality just by varying an identifier. Verifications are labelled by result and operation type, queries by a fixed query name, and the breaker gauges aggregate across contexts. Per-issuer detail remains available through the existing getCircuitBreakerMetrics() snapshot. Tests assert the new series; the unit and e2e suites now mock ./metrics.js, matching how the rest of the repo isolates the registry.
getPoolerStats() walks the pg pool, the query cache and the rate-limiter window map on every call, so a metrics scrape at the standard interval turns a cheap read into a full state walk per scrape. It is now fronted by a bounded TTL cache (1s, configurable via DB_POOLER_STATS_CACHE_TTL_MS) exposed as getCachedPoolerStats(), with invalidatePoolerStatsCache() and getPoolerStatsCacheStats() alongside it. getPoolerStats() itself is deliberately left uncached. Callers that need a value guaranteed to reflect the current instant -- the circuit-breaker and fallback-mode assertions in the pooler suite among them -- keep reading the live snapshot, and skipCache bypasses the cache for one-off callers. Four new series observe the cache: hits, misses, evictions and size. The existing test mock for ./metrics.js is extended to cover them, since an unlisted export would be undefined at runtime.
matteorossi-codes
force-pushed
the
fix/issues-1050-1051-1053-1055
branch
from
September 25, 2026 20:53
dd65650 to
b78977e
Compare
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.
Summary
Implements four Asset Issuer / Database Pooler issues. One commit per issue.
Changes
#1050 — Asset Issuer query caching (
backend/src/lib/asset-issuer.js)getIssuerStatsandgetAssetIssuerHealthMetricsre-queried the database on every call. Both are aggregate reads over payment rows that change slowly, so they now sit behind a bounded TTL cache (60s, 500 entries, oldest-first eviction), keyed per issuer and per merchant.Expired entries are dropped on read rather than only on write, and failed reads are never cached.
logAssetIssuerVerificationinvalidates exactly the issuer and merchant keys a verification write can affect.invalidateQueryCache()with no arguments clears everything; a call that names neither key is a no-op, so a write with no known issuer cannot wipe the cache for other callers.#1051 — Asset Issuer end-to-end testing (
backend/tests/asset-issuer-e2e.test.js)18 tests driving the module through its public entry points — the
AssetIssuerManagerfacade, the exported singleton and the rate-limit factory — rather than the per-class unit tests already insrc/lib/asset-issuer.test.js. Horizon, Postgres, Redis and the logger are mocked, so no network or database is required.Covers the verification flow, on-chain issuer confirmation, merchant issuer configuration, verification logging, degradation and circuit-breaker recovery, dead-letter handling, and the module surface.
#1053 — Granular metrics for Asset Issuer (
backend/src/lib/metrics.js,asset-issuer.js)Nine new Prometheus series, wired into the module: verification counts and latency, query-cache hit/miss/eviction/invalidation counters and a size gauge, per-query duration, error-recovery outcomes, aggregated circuit-breaker state gauges, and a dead-letter queue size gauge.
Per-issuer and per-transaction detail is deliberately not exported as label values. Issuers, merchants and transaction hashes are unbounded, so labelling by them would let a caller grow series cardinality just by varying an identifier — the same reasoning behind #1058. Verifications are labelled by result and operation type, queries by a fixed query name, and the breaker gauges aggregate across contexts. Per-issuer detail stays available via the existing
getCircuitBreakerMetrics()snapshot.#1055 — Database Pooler stats caching (
backend/src/lib/db-pooler-optimized.js)getPoolerStats()walks the pg pool, the query cache and the rate-limiter window map on every call, so a metrics scrape at the standard interval turns a cheap read into a full state walk per scrape. It is now fronted by a bounded TTL cache (1s, configurable viaDB_POOLER_STATS_CACHE_TTL_MS), exposed asgetCachedPoolerStats()withinvalidatePoolerStatsCache()andgetPoolerStatsCacheStats().getPoolerStats()is deliberately left uncached: callers that need a value guaranteed to reflect the current instant keep reading the live snapshot, andskipCachebypasses the cache for one-off callers. Four new series observe the cache (hits, misses, evictions, size).Notes
asset-issuer.test.jsand the new e2e suite now mock./metrics.js, matching how the rest of the repo isolates the registry.db-pooler-optimized.test.js's existing mock is extended with the four new pooler series, since an unlisted export would beundefinedat runtime.Issue #889andAssetIssuerManagerblocks clear the new cache inbeforeEach. Those tests assert onmockQueryWithRetry.mock.calls[0]after a single call; once the reads are cached, a leftover entry from an earlier test would serve from cache, issue no query, and leavecalls[0]belonging to whichever test ran first.db-pooler-optimized.jsandasset-issuer.jsare not imported by any non-test file, so this adds no new load-time cost to the running app.Verification
Code review only.
npm test/vitestwas not run — the environment has nonode_modulesand this change installs no dependencies. Every edited file was checked withnode --checkfor syntax.Two behaviour changes were reasoned through by hand because they interact with existing assertions, and are worth a reviewer's attention:
verifyOperationnow records a verification metric on the cache-hit path. The in-flight coalescing path deliberately does not record, so a coalesced call is counted once rather than twice.getIssuerStats/getAssetIssuerHealthMetricsaccept{ skipCache }; the existing call sites pass no options, so default behaviour is a cache read then a query on miss.Closes #1050
Closes #1051
Closes #1053
Closes #1055