fix(billing): add network error recovery for transaction retrieval#2559
fix(billing): add network error recovery for transaction retrieval#2559
Conversation
📝 WalkthroughWalkthroughAdds a transaction-recovery path to batch-signing-client: on retriable network/socket failures while fetching a broadcast tx, the service retries with exponential backoff (maxDelay 10s) to recover the IndexedTx; non-network errors still propagate. Tests added and Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant BatchSigningClient
participant Broadcaster
participant NodeAPI
Client->>BatchSigningClient: signAndBroadcast(tx)
BatchSigningClient->>Broadcaster: broadcast(tx)
Broadcaster-->>BatchSigningClient: txHash
BatchSigningClient->>NodeAPI: getTx(txHash)
alt getTx succeeds
NodeAPI-->>BatchSigningClient: IndexedTx
BatchSigningClient-->>Client: return IndexedTx
else getTx fails with retriable network/socket error
NodeAPI-->>BatchSigningClient: network error
BatchSigningClient->>BatchSigningClient: log recovery start
BatchSigningClient->>BatchSigningClient: txRecoveryExecutor (retry/backoff)
BatchSigningClient->>NodeAPI: getTx(txHash) (retries)
alt retry succeeds
NodeAPI-->>BatchSigningClient: IndexedTx
BatchSigningClient->>BatchSigningClient: log recovery success
BatchSigningClient-->>Client: return IndexedTx
else all retries fail
BatchSigningClient->>BatchSigningClient: log recovery failure
BatchSigningClient-->>Client: throw SIGN_AND_BROADCAST_TX_NOT_FOUND
end
else getTx fails non-network error
NodeAPI-->>BatchSigningClient: non-network error
BatchSigningClient-->>Client: throw original error
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In
`@apps/api/src/billing/lib/batch-signing-client/batch-signing-client.service.ts`:
- Around line 399-406: The tryRecoverTransaction method currently may return
undefined because getTxExecutor.execute() yields IndexedTx | undefined while the
method signature promises IndexedTx | null; change the implementation in
tryRecoverTransaction to await the executor result into a variable (e.g., const
tx = await this.getTxExecutor.execute(() => this.client.getTx(hash))) and return
tx ?? null, and ensure the catch block also returns null so the method never
leaks undefined and always conforms to IndexedTx | null; keep the existing
initial delay and use the same getTxExecutor.execute and client.getTx calls.
apps/api/src/billing/lib/batch-signing-client/batch-signing-client.service.ts
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In
`@apps/api/src/billing/lib/batch-signing-client/batch-signing-client.service.spec.ts`:
- Around line 166-168: The test's assertion doesn't enforce the "only once"
intent—replace the loose check expect(client.getTx).toHaveBeenCalled() with a
precise call count assertion expect(client.getTx).toHaveBeenCalledTimes(1) so
the test verifies client.getTx was invoked exactly once (no recovery attempts);
update the assertion in the batch-signing-client.service.spec.ts test
referencing client.getTx.
🧹 Nitpick comments (3)
apps/api/src/billing/lib/batch-signing-client/batch-signing-client.service.spec.ts (3)
99-124: Consider using try/finally for fake timer cleanup.If the test throws before reaching
jest.useRealTimers(), fake timers will leak to subsequent tests and may cause flaky failures. Wrap the test body or useafterEachfor cleanup.♻️ Suggested pattern
it("should recover transaction when getTx fails with network error but tx exists on chain", async () => { jest.useFakeTimers(); + try { const granter = createAkashAddress(); // ... test body ... expect(client.getTx).toHaveBeenCalledTimes(2); + } finally { jest.useRealTimers(); + } });Or alternatively, add cleanup to the describe block:
afterEach(() => { jest.useRealTimers(); });Also applies to: 126-151
107-111: Consider reducing inline comments.Per coding guidelines, unnecessary comments should be avoided. The mock setup is self-explanatory from method names like
mockRejectedValueOnceandmockResolvedValueOnce. Consider removing or consolidating comments.♻️ Example simplification
- // Reset getTx mock to simulate network error then recovery client.getTx.mockReset(); client.getTx - .mockRejectedValueOnce(new Error("TypeError: fetch failed")) // First call fails with network error - .mockResolvedValueOnce(testData.tx); // Recovery call succeeds + .mockRejectedValueOnce(new Error("TypeError: fetch failed")) + .mockResolvedValueOnce(testData.tx);Also applies to: 134-138, 159-162
99-99: Test descriptions use "should" prefix.Per coding guidelines, test descriptions should use present simple, 3rd person singular without prepending "should." However, this is consistent with existing tests in the file.
♻️ Example following guidelines
- it("should recover transaction when getTx fails with network error but tx exists on chain", async () => { + it("recovers transaction when getTx fails with network error but tx exists on chain", async () => { - it("should recover transaction when getTx fails with socket error", async () => { + it("recovers transaction when getTx fails with socket error", async () => { - it("should not attempt recovery for non-network errors", async () => { + it("does not attempt recovery for non-network errors", async () => {Note: Existing tests also use "should" prefix, so this would be a broader refactor affecting the entire file. As per coding guidelines.
Also applies to: 126-126, 153-153
apps/api/src/billing/lib/batch-signing-client/batch-signing-client.service.spec.ts
Outdated
Show resolved
Hide resolved
Codecov Report❌ Patch coverage is
❌ Your project status has failed because the head coverage (79.29%) is below the target coverage (80.00%). You can increase the head coverage or adjust the target coverage. Additional details and impacted files@@ Coverage Diff @@
## main #2559 +/- ##
==========================================
+ Coverage 50.76% 50.78% +0.02%
==========================================
Files 1069 1069
Lines 29728 29745 +17
Branches 6583 6595 +12
==========================================
+ Hits 15091 15107 +16
+ Misses 14286 14276 -10
- Partials 351 362 +11
🚀 New features to boost your workflow:
|
apps/api/src/billing/lib/batch-signing-client/batch-signing-client.service.ts
Outdated
Show resolved
Hide resolved
apps/api/src/billing/lib/batch-signing-client/batch-signing-client.service.ts
Outdated
Show resolved
Hide resolved
apps/api/src/billing/lib/batch-signing-client/batch-signing-client.service.ts
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In
`@apps/api/src/billing/lib/batch-signing-client/batch-signing-client.service.ts`:
- Around line 376-385: In tryRecoverTransaction, don't swallow all errors — only
convert retriable/network errors into null; rethrow any other failures. Inside
the catch for the this.txRecoveryExecutor.execute call in tryRecoverTransaction,
inspect the caught error (e.g., check error type, error.code/status or use a
helper like isNetworkError) and if it matches a retriable/network condition log
the TX_RECOVERY_FAILED and return null; otherwise rethrow the error so callers
can handle non-network failures. Ensure references remain to
tryRecoverTransaction, txRecoveryExecutor.execute, this.client.getTx and
this.logger.warn in your changes.
apps/api/src/billing/lib/batch-signing-client/batch-signing-client.service.ts
Show resolved
Hide resolved
… BatchSigningClientService
…s for network errors
…count for transaction retrieval
…s for retriable errors
…w non-network errors
03f667b to
e6307d0
Compare
apps/api/src/billing/lib/batch-signing-client/batch-signing-client.service.ts
Show resolved
Hide resolved
…th cause handling
Summary by CodeRabbit
Bug Fixes
New Features
Tests
Documentation
✏️ Tip: You can customize this high-level summary in your review settings.