Skip to content

Feat/fx cost aware selection new - #631

Merged
thlpkee20-wq merged 3 commits into
RevoraOrg:masterfrom
edochieblessing09-max:feat/fx-cost-aware-selection-new
Jul 29, 2026
Merged

Feat/fx cost aware selection new#631
thlpkee20-wq merged 3 commits into
RevoraOrg:masterfrom
edochieblessing09-max:feat/fx-cost-aware-selection-new

Conversation

@edochieblessing09-max

Copy link
Copy Markdown
Contributor

Closes #551

PR Description:

## Summary

Adds budget-aware FX rate provider selection that respects per-tenant monthly spend caps and gracefully degrades to cheaper providers when the cap is close.

## Changes

### New Files
- `src/services/fxProviderBudgetRegistry.ts` — Per-tenant monthly spend tracking with pluggable `SpendStore` interface and `InMemorySpendStore` for dev/test.
- `src/services/fxCostAwareSelector.ts``CostAwareRateSelector` that ranks providers by accuracy, enforces budget caps, degrades gracefully, records spend, and emits Prometheus metrics.
- `src/services/fxCostAwareSelection.test.ts` — Comprehensive test suite covering budget exhaustion, fallback edge cases, and multi-tenant isolation.
- `docs/fx-cost-aware-selection.md` — Full documentation with architecture diagram, config guide, security assumptions, and failure-path table.

## Design Decisions

### Never block distributions
`CostAwareRateSelector` enforces at construction time that at least one zero-cost provider exists. When all paid providers are exhausted, the free-tier provider (e.g., ECB) is always used.

### Fail-open on storage errors
`FxProviderBudgetRegistry.isProviderAvailable` and `isProviderNearLimit` catch storage exceptions and return safe defaults (`true` / `false` respectively) so a DB outage cannot freeze rate lookups.

### Cost values are operator-defined
`costUsdPerCall` is set in code, not derived from external inputs, preventing cost-manipulation attacks.

### Metric labels carry no PII
Only `provider_id` (not `tenant_id`) is used as a label dimension to protect user privacy.

## Emitted Metrics

| Metric | Type | Description |
|---|---|---|
| `fx.provider.spend_month` | Gauge | USD spend for a provider in the current calendar month |
| `fx.provider.degraded_total` | Counter | Selections where a cheaper provider was used due to budget pressure |
| `fx.provider.selection_total` | Counter | Total provider selection attempts |

## Security Assumptions

- `tenantId` is pre-authenticated by the caller — registry performs no auth.
- Negative spend increments throw `RangeError` immediately.
- Budget caps are hard limits, not soft advice.
- Storage failure → fail-open (providers treated as available).
- Missing free provider at startup → `Error` thrown in constructor.

- Add FxProviderBudgetRegistry: tracks per-tenant monthly spend per
  provider using a pluggable SpendStore interface; enforces monthlyCapUsd
  caps with configurable degradationThreshold (default 90 %).

- Add CostAwareRateSelector: ranks providers by accuracyRank (desc),
  skips exhausted providers, degrades to cheaper alternatives when near
  budget limit, records spend on every API call, and emits:
    * fx.provider.spend_month gauge (spend in USD this month)
    * fx.provider.degraded_total  counter (budget-pressure degradations)
    * fx.provider.selection_total counter (all selections)

- Add InMemorySpendStore: single-process store for dev/test; production
  deployments should wire a Postgres-backed implementation.

- Add docs/fx-cost-aware-selection.md covering architecture, config,
  security assumptions, abuse/failure paths, and Postgres schema example.

- Add src/services/fxCostAwareSelection.test.ts with comprehensive
  test suite (>= 95 % coverage target) covering:
    * Budget registry CRUD and cap enforcement
    * Normal provider selection (most accurate first)
    * Near-limit and exhaustion degradation
    * Budget cap exhaustion never blocks distributions
    * Provider error / null rate handling
    * Metric emission for gauge and counters
    * Multi-tenant isolation
    * Security edge cases (negative spend, storage failures, tenant
      injection, fail-open behaviour)
@drips-wave

drips-wave Bot commented Jul 28, 2026

Copy link
Copy Markdown

@edochieblessing09-max 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! 🚀

Learn more about application limits

@thlpkee20-wq
thlpkee20-wq merged commit e5c3af6 into RevoraOrg:master Jul 29, 2026
1 check failed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Exchange rate provider failover: cost-aware provider selection with monthly budget cap

2 participants