Skip to content

fix: fixes timeout for communication with provider-proxy#2820

Merged
stalniy merged 1 commit intomainfrom
fix/provider-proxy-service
Feb 26, 2026
Merged

fix: fixes timeout for communication with provider-proxy#2820
stalniy merged 1 commit intomainfrom
fix/provider-proxy-service

Conversation

@stalniy
Copy link
Contributor

@stalniy stalniy commented Feb 25, 2026

Why

The same timeout was passed to provider-proxy (which is per attempt timeout in case provider API doesn't respond) and to actual request timeout. This resulted in provider-proxy retries being ignored, in case of provider API timing out on the 1st attempt.

What

Summary by CodeRabbit

  • Bug Fixes

    • Adjusted timeout configuration for provider operations, reducing timeout values from 30 to 15 seconds for manifest and lease operations.
    • Improved timeout scaling logic to better manage per-attempt and total timeout handling.
  • Tests

    • Updated test suite to validate new timeout behavior.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 25, 2026

📝 Walkthrough

Walkthrough

Timeout handling in provider services is refactored to decouple per-attempt and total timeout values. Per-attempt timeouts are sent in request payloads, while total timeouts are multiplied by 5 in HTTP options. Timeout defaults are reduced from 30,000 ms to 15,000 ms, and tests are enhanced with fake timer controls for better timing assertions.

Changes

Cohort / File(s) Summary
Timeout Handling Implementation
apps/api/src/provider/services/provider/provider-proxy.service.ts, apps/api/src/provider/services/provider/provider.service.ts
Removed PROVIDER_PROXY_MAX_TIMEOUT constant. Decoupled per-attempt timeout (in payload) from total timeout (5x multiplier in HTTP options). Replaced timers/promises import with local delay helper. Reduced timeout defaults from 30,000 ms to 15,000 ms in manifest and lease status API calls.
Timeout Test Updates
apps/api/src/provider/services/provider/provider-proxy.service.spec.ts, apps/api/src/provider/services/provider/provider.service.spec.ts
Updated timeout assertions to expect 5x multiplied values. Introduced vitest fake timers with vi.useFakeTimers() and vi.runAllTimersAsync() in retry-related tests. Added global afterEach hook to reset fake timers. Enhanced assertions to handle asynchronous results with resolves matchers.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 Timeout tales of ours so true,
Per-attempt splits from total's due,
Multiply by five, we scale just right,
Timers fake dance through the test night,
Faster defaults, cleaner the way!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description provides a clear 'Why' section explaining the timeout issue, but the 'What' section is incomplete with only template comments and no actual explanation of the changes made. Complete the 'What' section by describing the specific timeout changes: per-attempt timeout in payload, total timeout (5x) in HTTP options, and reduced manifest timeout from 30s to 15s.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: fixing timeout handling for provider-proxy communication by decoupling per-attempt and total request timeouts.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/provider-proxy-service

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/api/src/provider/services/provider/provider-proxy.service.spec.ts (1)

52-59: ⚠️ Potential issue | 🟡 Minor

Stale test description: "when within max"

The MAX_TIMEOUT cap was removed in this PR; there is no longer a "within max" condition. Update the description to reflect the actual behavior.

✏️ Suggested fix
-    it("passes timeout in both payload and config when within max", async () => {
+    it("passes timeout in payload and scales it by 5x in HTTP config", async () => {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/api/src/provider/services/provider/provider-proxy.service.spec.ts`
around lines 52 - 59, Update the stale test title: change the it(...)
description in the test that calls setup({ timeout }) and invokes
service.request(url, options) (the test currently reads "passes timeout in both
payload and config when within max") to accurately reflect current behavior
(e.g., "passes timeout in both payload and config") so the test name matches the
behavior exercised by httpClient.post mock and the expectations on
service.request.
🧹 Nitpick comments (3)
apps/api/src/provider/services/provider/provider.service.spec.ts (1)

152-166: Consider using rejects instead of manually unwrapping the error

The .catch(error => ({ error })) wrapper + manual cast pattern works, but the standard vitest idiom for asserting on a rejection is await expect(promise).rejects.toThrow(...). It also removes the explicit , 15000 timeout hint that is redundant when fake timers are active (real time does not elapse).

♻️ Suggested refactor
-      const result = service
-        .sendManifest({
-          provider: provider.owner,
-          dseq,
-          manifest,
-          auth: await service.toProviderAuth({ walletId: wallet.id, provider: provider.owner })
-        })
-        .catch(error => ({ error }));
-
+      const result = service.sendManifest({
+        provider: provider.owner,
+        dseq,
+        manifest,
+        auth: await service.toProviderAuth({ walletId: wallet.id, provider: provider.owner })
+      });
+
       await vi.runAllTimersAsync();
-      const { error } = (await result) as { error: Error };
-      expect(error.message).toContain("no lease for deployment");
+      await expect(result).rejects.toThrow("no lease for deployment");

       expect(providerProxyService.request).toHaveBeenCalledTimes(3);
-    }, 15000);
+    });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/api/src/provider/services/provider/provider.service.spec.ts` around
lines 152 - 166, Replace the manual .catch wrapper and manual error extraction
with Vitest's rejects idiom: call the promise returned by
service.sendManifest(...) and assert with await
expect(promise).rejects.toThrow("no lease for deployment") after advancing
timers with await vi.runAllTimersAsync(); remove the surrounding .catch(error =>
({ error })) and the redundant test timeout parameter (", 15000"); keep the
existing assertion that providerProxyService.request was called 3 times to
preserve call-count verification.
apps/api/src/provider/services/provider/provider-proxy.service.ts (1)

54-59: Extract the 5 multiplier as a named constant

The scalar 5 that converts per-attempt timeout to total-request timeout is a magic number. Naming it makes the intent clearer and ensures the value is changed in one place (the test for 5 * timeout would also benefit).

♻️ Suggested refactor
+  private static readonly TIMEOUT_ATTEMPT_MULTIPLIER = 5;
+
   async request<T>(url: string, options: ProviderProxyPayload): Promise<T> {
     const { chainNetwork, providerIdentity, timeout, ...params } = options;
     const response = await this.#httpClient.post(
       "/",
       {
         ...params,
         method: options.method || "GET",
         url: providerIdentity.hostUri + url,
         providerAddress: providerIdentity.owner,
         network: chainNetwork,
-        timeout // this is per attempt timeout on provider-proxy side
+        timeout
       },
       {
         ...(timeout && {
-          // this is total timeout for all attempts to communicate with the provider API, and it should be much higher than per attempt timeout
-          timeout: timeout * 5
+          timeout: timeout * ProviderProxyService.TIMEOUT_ATTEMPT_MULTIPLIER
         })
       }
     );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/api/src/provider/services/provider/provider-proxy.service.ts` around
lines 54 - 59, The literal multiplier 5 used to compute the total request
timeout is a magic number; extract it to a named constant (e.g.
TOTAL_TIMEOUT_MULTIPLIER) and replace the expression timeout * 5 with timeout *
TOTAL_TIMEOUT_MULTIPLIER in the object that sets timeout (the code block that
spreads ...(timeout && { timeout: timeout * 5 })). Also update any tests that
assert on the numeric value to reference the new constant so the behavior stays
consistent and the intent is clear.
apps/api/src/provider/services/provider/provider.service.ts (1)

91-91: Inconsistent numeric literal formatting

Line 91 uses 15_000 (with separator) while line 140 uses 15000 (without). Prefer a consistent style across both call sites.

✏️ Suggested fix
-      timeout: 15000
+      timeout: 15_000

Also applies to: 140-141

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/api/src/provider/services/provider/provider.service.ts` at line 91, Two
numeric literals for the same timeout are formatted inconsistently: one uses
15_000 and another uses 15000; pick a single style and make both call sites
consistent by updating the other occurrence. Locate the timeout property in
provider.service.ts (the options object where timeout: 15_000 is set) and the
other call site that currently uses 15000, then change the 15000 to match your
chosen style (either 15_000 or 15000) so both timeout literals are identical.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@apps/api/src/provider/services/provider/provider-proxy.service.spec.ts`:
- Around line 52-59: Update the stale test title: change the it(...) description
in the test that calls setup({ timeout }) and invokes service.request(url,
options) (the test currently reads "passes timeout in both payload and config
when within max") to accurately reflect current behavior (e.g., "passes timeout
in both payload and config") so the test name matches the behavior exercised by
httpClient.post mock and the expectations on service.request.

---

Nitpick comments:
In `@apps/api/src/provider/services/provider/provider-proxy.service.ts`:
- Around line 54-59: The literal multiplier 5 used to compute the total request
timeout is a magic number; extract it to a named constant (e.g.
TOTAL_TIMEOUT_MULTIPLIER) and replace the expression timeout * 5 with timeout *
TOTAL_TIMEOUT_MULTIPLIER in the object that sets timeout (the code block that
spreads ...(timeout && { timeout: timeout * 5 })). Also update any tests that
assert on the numeric value to reference the new constant so the behavior stays
consistent and the intent is clear.

In `@apps/api/src/provider/services/provider/provider.service.spec.ts`:
- Around line 152-166: Replace the manual .catch wrapper and manual error
extraction with Vitest's rejects idiom: call the promise returned by
service.sendManifest(...) and assert with await
expect(promise).rejects.toThrow("no lease for deployment") after advancing
timers with await vi.runAllTimersAsync(); remove the surrounding .catch(error =>
({ error })) and the redundant test timeout parameter (", 15000"); keep the
existing assertion that providerProxyService.request was called 3 times to
preserve call-count verification.

In `@apps/api/src/provider/services/provider/provider.service.ts`:
- Line 91: Two numeric literals for the same timeout are formatted
inconsistently: one uses 15_000 and another uses 15000; pick a single style and
make both call sites consistent by updating the other occurrence. Locate the
timeout property in provider.service.ts (the options object where timeout:
15_000 is set) and the other call site that currently uses 15000, then change
the 15000 to match your chosen style (either 15_000 or 15000) so both timeout
literals are identical.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between babcc4e and 63ba347.

📒 Files selected for processing (4)
  • apps/api/src/provider/services/provider/provider-proxy.service.spec.ts
  • apps/api/src/provider/services/provider/provider-proxy.service.ts
  • apps/api/src/provider/services/provider/provider.service.spec.ts
  • apps/api/src/provider/services/provider/provider.service.ts

@codecov
Copy link

codecov bot commented Feb 25, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 53.38%. Comparing base (babcc4e) to head (63ba347).
⚠️ Report is 11 commits behind head on main.
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2820      +/-   ##
==========================================
- Coverage   54.24%   53.38%   -0.87%     
==========================================
  Files        1020      985      -35     
  Lines       23637    22803     -834     
  Branches     5796     5699      -97     
==========================================
- Hits        12823    12173     -650     
+ Misses       9435     9251     -184     
  Partials     1379     1379              
Flag Coverage Δ *Carryforward flag
api 76.95% <100.00%> (-0.04%) ⬇️
deploy-web 36.82% <ø> (ø) Carriedforward from babcc4e
log-collector ?
notifications 85.56% <ø> (ø) Carriedforward from babcc4e
provider-console 81.48% <ø> (ø) Carriedforward from babcc4e
provider-proxy 85.93% <ø> (ø) Carriedforward from babcc4e
tx-signer ?

*This pull request uses carry forward flags. Click here to find out more.

Files with missing lines Coverage Δ
...ovider/services/provider/provider-proxy.service.ts 100.00% <100.00%> (ø)
...src/provider/services/provider/provider.service.ts 94.38% <100.00%> (+0.06%) ⬆️

... and 36 files with indirect coverage changes

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@stalniy stalniy added this pull request to the merge queue Feb 26, 2026
Merged via the queue into main with commit 5ec2c57 Feb 26, 2026
53 of 54 checks passed
@stalniy stalniy deleted the fix/provider-proxy-service branch February 26, 2026 12:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants