Bug
All Soroban RPC calls in the Astera frontend fail immediately on the first error with no retry. Stellar Horizon and Soroban RPC servers occasionally return transient errors (rate limiting, momentary unavailability, network blips). A single transient error currently causes the entire page component to enter an error state that requires a full page reload to recover.
Impact
- User sees "Error loading data" for a transient 500ms RPC outage
- No automatic recovery without manual refresh
- Dashboard unusable during any RPC instability
Fix
Add retry logic to SWR hooks with exponential backoff:
```ts
// frontend/lib/swrConfig.ts
export const swrConfig: SWRConfiguration = {
onErrorRetry: (error, key, config, revalidate, { retryCount }) => {
// Don't retry on 404 (not found — permanent)
if (error.status === 404) return;
// Retry up to 3 times with exponential backoff
if (retryCount >= 3) return;
setTimeout(() => revalidate({ retryCount }), 1000 * Math.pow(2, retryCount));
},
errorRetryCount: 3,
errorRetryInterval: 1000,
};
```
Apply this config globally in `_app.tsx` or `layout.tsx` via `SWRConfig`.
For one-off fetch calls, wrap with a retry utility:
```ts
async function withRetry(fn: () => Promise, retries = 3): Promise {
for (let i = 0; i < retries; i++) {
try { return await fn(); }
catch (e) { if (i === retries - 1) throw e; await sleep(1000 * 2**i); }
}
throw new Error('unreachable');
}
```
Acceptance Criteria
References
- `frontend/lib/` — API/SWR hook configuration
- SWR documentation: `onErrorRetry`
Bug
All Soroban RPC calls in the Astera frontend fail immediately on the first error with no retry. Stellar Horizon and Soroban RPC servers occasionally return transient errors (rate limiting, momentary unavailability, network blips). A single transient error currently causes the entire page component to enter an error state that requires a full page reload to recover.
Impact
Fix
Add retry logic to SWR hooks with exponential backoff:
```ts
// frontend/lib/swrConfig.ts
export const swrConfig: SWRConfiguration = {
onErrorRetry: (error, key, config, revalidate, { retryCount }) => {
// Don't retry on 404 (not found — permanent)
if (error.status === 404) return;
// Retry up to 3 times with exponential backoff
if (retryCount >= 3) return;
setTimeout(() => revalidate({ retryCount }), 1000 * Math.pow(2, retryCount));
},
errorRetryCount: 3,
errorRetryInterval: 1000,
};
```
Apply this config globally in `_app.tsx` or `layout.tsx` via `SWRConfig`.
For one-off fetch calls, wrap with a retry utility:
```ts
async function withRetry(fn: () => Promise, retries = 3): Promise {
for (let i = 0; i < retries; i++) {
try { return await fn(); }
catch (e) { if (i === retries - 1) throw e; await sleep(1000 * 2**i); }
}
throw new Error('unreachable');
}
```
Acceptance Criteria
References