Skip to content

Fix Garmin rate-limit retry collisions and reduce Connect API pressure - #1364

Merged
Asherlc merged 11 commits into
mainfrom
Asherlc/garmin-100-rate-limit
Jun 25, 2026
Merged

Asherlc merged 11 commits into
mainfrom
Asherlc/garmin-100-rate-limit

Conversation

@Asherlc

@Asherlc Asherlc commented Jun 24, 2026

Copy link
Copy Markdown
Owner

Summary

  • Route cooldown retries through enqueueSyncJob and deduplicate any preset job ID (including rate-limit retries), so scheduled sync, step-chain continuations, and delayed retries share one enqueue/throttle path.
  • Reduce Garmin Connect API pressure by caching OAuth consumer credentials, bypassing adaptive rate limits for the S3 consumer fetch, slowing HTTP/job pacing (5s), and lowering the inferred request budget.
  • Extend Garmin's fallback cooldown to 2 hours (above the 30-minute scheduler) and skip scheduled sync when Garmin/WHOOP step-chain jobs are already queued.

Test plan

  • pnpm exec vitest run src/jobs/enqueue-sync-job.test.ts src/jobs/sync-request-job.test.ts src/jobs/process-sync-job.test.ts src/jobs/process-scheduled-sync-job.test.ts
  • pnpm exec vitest run packages/garmin-connect/src/client.test.ts src/providers/garmin.test.ts src/jobs/provider-rate-limit-cooldown.test.ts
  • Verify a rate-limited Garmin sync schedules one delayed retry and does not enqueue a parallel scheduled sync while step-chain jobs are pending

Made with Cursor

Summary by Sourcery

Optimize Garmin sync behavior to reduce Connect API load and avoid redundant or colliding retry/scheduled jobs.

New Features:

  • Bypass adaptive rate limiting for Garmin OAuth consumer S3 requests via a dedicated fetch wrapper.
  • Cache Garmin OAuth consumer credentials at the module level and reuse them across client instances.

Bug Fixes:

  • Deduplicate cooldown-delayed Garmin sync jobs by reusing existing delayed jobs when present.
  • Skip scheduled sync enqueue for step-chain providers when in-flight sync jobs already exist for a user.

Enhancements:

  • Increase Garmin Connect request throttling and job limiter intervals to slow request pacing and reduce API pressure.
  • Switch Garmin adaptive rate limiting to provider-scoped budgeting and lower the inferred request budget for Garmin.
  • Route rate-limit cooldown retries through the standard sync enqueue path instead of directly enqueueing queue jobs.
  • Extend Garmin's fallback rate-limit cooldown window to two hours to avoid immediate rescheduling after delayed retries.

Tests:

  • Add tests covering OAuth consumer caching behavior and cache reset for GarminConnectClient.
  • Add tests verifying cooldown job deduplication, in-flight job skipping for scheduled sync, updated cooldown timings, and revised queue throttling.

Summary by cubic

Fixes Garmin rate-limit retry collisions and reduces Connect API pressure. Retries no longer pile up, pacing is slower and shared, and the OAuth consumer fetch bypass is restricted to the S3 host.

  • Bug Fixes
    • Route cooldown retries through enqueueSyncJob with provider-scoped job IDs; reuse existing delayed cooldown jobs instead of enqueueing duplicates.
    • Skip scheduled syncs for step-chain providers when sync jobs are already queued; use typed queue getters (active/waiting/delayed) to check pending work.
    • Use provider-scoped rate limiting for Garmin; set HTTP throttle to 5s, job limiter to 1 per 5s, inferred budget to 20, and extend fallback cooldown to 2h.
    • Bypass adaptive limiting only for OAuth consumer requests to thegarth.s3.amazonaws.com; cache the consumer per fetch via a WeakMap and validate the S3 JSON response.

Written for commit b4af350. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • Bug Fixes
    • Improved Garmin sync reliability by reducing duplicate job enqueues and better handling existing delayed or in-flight sync work.
    • Updated Garmin request handling to avoid unnecessary retries and to treat rate limits more conservatively, helping reduce failed sync attempts.
    • Garmin OAuth-related requests now bypass the shared throttle when appropriate, which should make sign-in and sync flows more consistent.

Unify cooldown retries through enqueueSyncJob with shared dedup, slow Garmin pacing, cache OAuth consumer credentials, and skip scheduled sync when step-chain jobs are already queued.

Co-authored-by: Cursor <cursoragent@cursor.com>
@qodo-code-review

Copy link
Copy Markdown

Qodo reviews are paused for this user.

Troubleshooting steps vary by plan Learn more →

On a Teams plan?
Reviews resume once this user has a paid seat and their Git account is linked in Qodo.
Link Git account →

Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center?
These require an Enterprise plan - Contact us
Contact us →

@coderabbitai

coderabbitai Bot commented Jun 24, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Garmin Connect requests now bypass provider rate limiting for OAuth consumer fetches, cache consumer credentials across client instances, and use updated Garmin throttle, limiter, and fallback cooldown values. Sync scheduling now uses request deduplication, provider-scoped cooldown job IDs, and queued-job checks for step-chain providers.

Changes

Garmin rate limits and sync scheduling

Layer / File(s) Summary
Garmin request routing and throttle defaults
packages/garmin-connect/src/*, packages/provider-http/src/*, src/providers/garmin*.ts, src/jobs/provider-queue-config.*
Garmin Connect requests bypass provider rate limiting for OAuth consumer requests, consumer loads are cached, and Garmin throttle, queue limiter, and inferred budget defaults move to 5 seconds and 20.
Delayed retry cooldown IDs
src/jobs/provider-rate-limit-cooldown.*, src/jobs/enqueue-sync-job.*, src/jobs/sync-request-job.*, src/jobs/process-sync-job.test.ts
Garmin fallback cooldown becomes 2 hours, provider-scope cooldown job IDs omit user segments, and delayed retry enqueueing now uses request deduplication.
Queued sync detection
src/lib/sync-request-queue.*, src/jobs/process-scheduled-sync-job.*
Provider sync job lookup now reads active, waiting, and delayed jobs, and scheduled sync processing skips step-chain providers when queued work already exists while tracking skipped counts.

Sequence Diagram(s)

Garmin consumer fetch flow

sequenceDiagram
  participant GarminProvider
  participant createGarminConnectFetch
  participant GarminConnectClient
  participant baseFetchFn
  participant rateLimitedFetchFn
  GarminProvider->>createGarminConnectFetch: build authFetch and sync fetchFn
  GarminConnectClient->>createGarminConnectFetch: first fromTokens request for oauth_consumer.json
  createGarminConnectFetch->>baseFetchFn: bypass rate limit for oauth consumer host
  GarminConnectClient->>GarminConnectClient: cache oauth consumer
  GarminConnectClient->>createGarminConnectFetch: later Garmin API request
  createGarminConnectFetch->>rateLimitedFetchFn: use Garmin rate-limited fetch
Loading

Queued sync skip flow

sequenceDiagram
  participant processScheduledSyncJob
  participant listProviderSyncJobsForUser
  participant getProviderSyncQueue
  processScheduledSyncJob->>listProviderSyncJobsForUser: check queued sync jobs for user/provider
  listProviderSyncJobsForUser->>getProviderSyncQueue: getActive()
  listProviderSyncJobsForUser->>getProviderSyncQueue: getWaiting()
  listProviderSyncJobsForUser->>getProviderSyncQueue: getDelayed(0, 49)
  listProviderSyncJobsForUser-->>processScheduledSyncJob: filtered jobs
  alt jobs already queued for a step-chain provider
    processScheduledSyncJob-->>processScheduledSyncJob: skip enqueue and increment skippedDueToInFlight
  else no queued jobs
    processScheduledSyncJob->>getProviderSyncQueue: add sync job
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • Asherlc/dofek#1360: Updates the same step-chain sync dedup path, including listProviderSyncJobsForUser and scheduled sync skipping.
  • Asherlc/dofek#1313: Introduced the request-dedup enqueue path that scheduleDelayedSyncJob now uses for delayed retries.
  • Asherlc/dofek#1248: Changes the same provider-rate-limit cooldown job ID construction logic in src/jobs/provider-rate-limit-cooldown.ts.

Suggested labels

area/web, area/providers, type/bug

Suggested reviewers

  • cubic-dev-ai
🚥 Pre-merge checks | ✅ 1 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Title check ⚠️ Warning The title matches the change, but it is missing the required area prefix and is exactly 70 characters, which violates the under-70-char rule. Prefix it with the relevant area, e.g. [server], and shorten it to fewer than 70 characters without trailing punctuation.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch Asherlc/garmin-100-rate-limit

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@sourcery-ai

sourcery-ai Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Reviewer's Guide

Routes Garmin rate-limit retries through the shared sync enqueue/dedup path, reduces overall Garmin Connect API pressure (throttling, inferred budgets, queue limiter), and hardens scheduled sync behavior by extending Garmin cooldowns, preventing duplicate delayed jobs, and skipping fan-out when step-chain jobs are already in flight.

Sequence diagram for scheduled sync skipping in-flight step-chain Garmin jobs

sequenceDiagram
  participant Scheduler as ScheduledSyncJob
  participant Process as processScheduledSyncJob
  participant StepCheck as isStepChainSyncProvider
  participant ListJobs as listProviderSyncJobsForUser
  participant Enqueue as enqueueSyncJob

  Scheduler->>Process: processScheduledSyncJob(job, db)
  loop users/providers
    Process->>StepCheck: isStepChainSyncProvider(providerId)
    alt provider is step-chain
      Process->>ListJobs: listProviderSyncJobsForUser(providerId, userId)
      ListJobs-->>Process: pendingJobs
      alt pendingJobs.length > 0
        Process-->>Process: skippedDueToInFlight++
        Process-->>Scheduler: logger.info Skipping providerId for userId
      else no pending jobs
        Process->>Enqueue: enqueueSyncJob(providerId, jobData)
        Enqueue-->>Process: job
        Process-->>Process: jobCount++
      end
    else provider not step-chain
      Process->>Enqueue: enqueueSyncJob(providerId, jobData)
      Enqueue-->>Process: job
      Process-->>Process: jobCount++
    end
  end
  Process-->>Scheduler: logger.info summary with skippedDueToInFlight
Loading

Sequence diagram for Garmin rate-limit delayed retry deduplication

sequenceDiagram
  actor Worker as RateLimitedSyncJob
  participant Schedule as scheduleDelayedSyncJob
  participant Enqueue as enqueueSyncJob
  participant Dedup as enqueueSyncJobWithRequestDedup
  participant Queue as getProviderSyncQueue
  participant JobStore as getJob

  Worker->>Schedule: scheduleDelayedSyncJob(jobData, cooldown)
  Schedule-->>Schedule: providerId = jobData.providerId ?? cooldown.providerId
  Schedule->>Enqueue: enqueueSyncJob(providerId, jobData with providerId)
  Enqueue->>Dedup: enqueueSyncJobWithRequestDedup(providerId, jobData, retryOptions, addJob, getJob)
  alt nextOptions.jobId is null and requestQuery exists
    Dedup-->>Dedup: buildSyncRequestJobId(...)
  end
  Dedup->>JobStore: getJob(nextOptions.jobId)
  alt existing job found
    JobStore-->>Dedup: existing
    Dedup->>existing: getState()
    alt state is delayed
      Dedup-->>Enqueue: return existing
      Enqueue-->>Schedule: existing
    else other state
      Dedup->>existing: remove()
      Dedup->>Queue: add(name, jobData, nextOptions)
      Queue-->>Dedup: newJob
      Dedup-->>Enqueue: newJob
      Enqueue-->>Schedule: newJob
    end
  else no existing job
    JobStore-->>Dedup: null
    Dedup->>Queue: add(name, jobData, nextOptions)
    Queue-->>Dedup: newJob
    Dedup-->>Enqueue: newJob
    Enqueue-->>Schedule: newJob
  end
  Schedule-->>Worker: cooldown.expiresAt.toISOString()
Loading

File-Level Changes

Change Details Files
Bypass adaptive rate limiting for static OAuth consumer fetches and cache consumer credentials across Garmin Connect client instances to reduce redundant calls.
  • Introduce isGarminOAuthConsumerRequest and createGarminConnectFetch to route OAuth consumer S3 requests around adaptive rate limiting while leaving other calls rate-limited.
  • Wrap Garmin auth and sync fetch functions with createGarminConnectFetch so oauth_consumer.json is fetched via the base fetch and all other calls use the adaptive rate-limited fetch.
  • Add a module-level cachedOAuthConsumer and oauthConsumerLoadPromise with resetGarminConnectTestCaches helper so consumer credentials are fetched once and reused across GarminConnectClient.fromTokens calls.
  • Add tests verifying OAuth consumer caching and cache reset between tests.
src/providers/garmin/provider.ts
packages/garmin-connect/src/client.ts
packages/garmin-connect/src/client.test.ts
Re-tune Garmin Connect throttling and inferred rate-limit behavior to be more conservative and slow down job scheduling.
  • Increase GARMIN_CONNECT_THROTTLE_MS and Garmin default provider throttle from 3s to 5s to space out API calls more aggressively.
  • Lower Garmin DEFAULT_PROVIDER_INFERRED_BUDGET to a constant 20 requests to reflect IP-based limits and reduce early request bursts.
  • Update provider queue configuration so Garmin's BullMQ limiter runs at max 1 job per 5s instead of 1 per 1s, and adjust tests accordingly.
packages/garmin-connect/src/client.ts
packages/provider-http/src/adaptive-rate-limit.ts
packages/provider-http/src/adaptive-rate-limit.test.ts
src/jobs/provider-queue-config.ts
src/jobs/provider-queue-config.test.ts
Route rate-limit cooldown retries through enqueueSyncJob with job-id deduplication so delayed retries reuse the same path as manual/scheduled sync requests and avoid duplicate jobs.
  • Change scheduleDelayedSyncJob to delegate to enqueueSyncJob with merged SyncJobData instead of directly adding to the provider queue with BullMQ options.
  • Extend enqueueSyncJobWithRequestDedup so it always computes a deterministic jobId when missing, but also handles a pre-set jobId by attempting to load an existing job and reusing delayed cooldown jobs instead of enqueueing duplicates.
  • Add tests to verify that cooldown-delayed jobs are reused (not duplicated) and that the cooldown store is consulted when scheduling delayed sync jobs.
src/jobs/enqueue-sync-job.ts
src/jobs/sync-request-job.ts
src/jobs/enqueue-sync-job.test.ts
src/jobs/sync-request-job.test.ts
Harden rate-limit cooldown semantics for Garmin by extending fallback cooldown duration and updating expectations in tests.
  • Increase Garmin's fallbackCooldownSeconds from 1h to 2h to exceed the 30-minute scheduled sync cadence and avoid immediate re-fan-out after a delayed retry.
  • Update ProviderRateLimitCooldownStore tests to assert the new cooldown expiry times, including multi-hit and reset scenarios.
src/jobs/provider-rate-limit-cooldown.ts
src/jobs/provider-rate-limit-cooldown.test.ts
Prevent scheduled sync fan-out from enqueueing duplicate jobs when step-chain providers (Garmin/WHOOP) already have in-flight sync jobs for a user.
  • Extend processScheduledSyncJob to, for step-chain providers, list existing sync jobs for a user and skip enqueue when any are pending, tracking a separate skippedDueToInFlight counter.
  • Augment logging to report per-user skip reasons and summarize both cooldown-skipped and in-flight-skipped counts in the final log line.
  • Add tests confirming scheduled sync is skipped when Garmin step-chain jobs are already queued and that the new log messages are emitted.
src/jobs/process-scheduled-sync-job.ts
src/jobs/process-scheduled-sync-job.test.ts
Align Garmin provider tests with provider-scoped rate limiting instead of user-scoped limits.
  • Update GarminProvider.sync tests to assert that createProviderRateLimitFetch is called with provider-scoped options (no userId/scope) and that GarminRateLimitError now carries provider-level scope information.
  • Adjust expectations around created rate-limit errors (message, retryAfterSeconds, and scope).
src/providers/garmin.test.ts

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@github-actions

github-actions Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Storybook previews for 19089c98 are ready:

This comment updates automatically on each PR push.

Co-authored-by: Cursor <cursoragent@cursor.com>

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hey - I've found 1 issue, and left some high level feedback:

  • The module-level OAuth consumer cache in garmin-connect/client.ts is global and keyed only by URL constant, so if fromTokens is ever used with different host values or differing fetchFn behavior (e.g., proxy, region, or test doubles), they will all share the same cached consumer; consider scoping the cache by host or by the effective consumer URL to avoid subtle cross-environment leakage.
  • In createGarminConnectFetch, the isGarminOAuthConsumerRequest check uses a simple includes(OAUTH_CONSUMER_HOST) on the stringified input; if other S3 URLs can contain that substring or if protocols/ports matter, you may want to parse as new URL(...) and compare hostname (and optionally pathname) instead to reduce the chance of accidentally bypassing adaptive rate limiting for unrelated requests.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The module-level OAuth consumer cache in `garmin-connect/client.ts` is global and keyed only by URL constant, so if `fromTokens` is ever used with different `host` values or differing `fetchFn` behavior (e.g., proxy, region, or test doubles), they will all share the same cached consumer; consider scoping the cache by host or by the effective consumer URL to avoid subtle cross-environment leakage.
- In `createGarminConnectFetch`, the `isGarminOAuthConsumerRequest` check uses a simple `includes(OAUTH_CONSUMER_HOST)` on the stringified input; if other S3 URLs can contain that substring or if protocols/ports matter, you may want to parse as `new URL(...)` and compare `hostname` (and optionally `pathname`) instead to reduce the chance of accidentally bypassing adaptive rate limiting for unrelated requests.

## Individual Comments

### Comment 1
<location path="src/providers/garmin/provider.ts" line_range="53-62" />
<code_context>

+const OAUTH_CONSUMER_HOST = "thegarth.s3.amazonaws.com";
+
+function isGarminOAuthConsumerRequest(input: RequestInfo | URL): boolean {
+  const url =
+    typeof input === "string"
+      ? input
+      : input instanceof URL
+        ? input.href
+        : input instanceof Request
+          ? input.url
+          : String(input);
+  return url.includes(OAUTH_CONSUMER_HOST);
+}
+
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Avoid substring matching for URL host detection to reduce false positives.

Using `url.includes(OAUTH_CONSUMER_HOST)` can misclassify requests when the host string appears in query params, paths, or inside another hostname. Prefer parsing the URL (e.g. `const { hostname } = new URL(url)`) and comparing `hostname` (and optionally `pathname`) to the expected values so routing only triggers for the intended host.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread src/providers/garmin/provider.ts Outdated
Comment thread src/providers/garmin/provider.ts Fixed
Asherlc and others added 5 commits June 24, 2026 16:25
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
- Fix listProviderSyncJobsForUser perf: use bounded typed getters instead of unbounded getJobs
- Fix provider-scoped cooldown jobId: strip userId so all users share one retry jobId
- Fix redundant cooldown re-check in scheduleDelayedSyncJob: call enqueueSyncJobWithRequestDedup directly
- Remove unused PENDING_SYNC_JOB_STATES constant
- Update all test mocks and assertions
Kills 34/37 mutants in Garmin provider rate-limit code.
Covers: catch-block headers guards, null/get-method headers,
OAuth consumer URL/Request bypass, init forwarding,
invalid URL handling, plain-object resolveRequestUrl path,
quota-exceeded Retry-After parsing.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/garmin-connect/src/client.ts`:
- Around line 51-55: The module-level test helper resetGarminConnectTestCaches
is being exported from production code, which should be removed. Keep the
cache-reset logic out of the public API in client.ts by deleting the export and
isolating tests through module isolation or a non-public cache design, while
preserving the behavior of cachedOAuthConsumer and oauthConsumerLoadPromise for
runtime use.
- Around line 230-235: The OAuth consumer response in the Garmin auth flow is
being cached without validation, so a malformed S3 payload can poison later
requests. In the OAuth consumer fetch logic in client.ts, parse the JSON with
the existing Zod schema before assigning to cachedOAuthConsumer, and only cache
the parsed result after it validates successfully. Keep the validation inside
the same fetch path that currently builds the OAuthConsumer value so invalid
data throws before caching.

In `@src/lib/sync-request-queue.ts`:
- Around line 11-17: The delayed-job deduplication in sync-request-queue’s job
lookup is bounded by queue.getDelayed(0, 49), which can miss duplicates beyond
the first 50 delayed entries. Update the job collection logic in the function
that gathers active, waiting, and delayed jobs to fetch all delayed jobs by
calling queue.getDelayed() with default arguments (or 0, -1), then keep
filtering by job.data.userId as before so duplicate sync jobs are always
detected.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: caaaf4a3-9098-40a5-936a-1f5c0e6fb2ab

📥 Commits

Reviewing files that changed from the base of the PR and between d2c9b8c and 7253434.

📒 Files selected for processing (22)
  • cspell.json
  • packages/garmin-connect/src/client.test.ts
  • packages/garmin-connect/src/client.ts
  • packages/provider-http/src/adaptive-rate-limit.test.ts
  • packages/provider-http/src/adaptive-rate-limit.ts
  • packages/web/src/pages/ProviderDetailPage.test.tsx
  • src/jobs/enqueue-sync-job.test.ts
  • src/jobs/enqueue-sync-job.ts
  • src/jobs/process-scheduled-sync-job.test.ts
  • src/jobs/process-scheduled-sync-job.ts
  • src/jobs/process-sync-job.test.ts
  • src/jobs/provider-queue-config.test.ts
  • src/jobs/provider-queue-config.ts
  • src/jobs/provider-rate-limit-cooldown.test.ts
  • src/jobs/provider-rate-limit-cooldown.ts
  • src/jobs/sync-request-job.test.ts
  • src/jobs/sync-request-job.ts
  • src/lib/sync-request-queue.test.ts
  • src/lib/sync-request-queue.ts
  • src/providers/garmin-connect-internal-sync.integration.test.ts
  • src/providers/garmin.test.ts
  • src/providers/garmin/provider.ts

Comment thread packages/garmin-connect/src/client.ts Outdated
Comment thread packages/garmin-connect/src/client.ts Outdated
Comment thread src/lib/sync-request-queue.ts
Asherlc added 4 commits June 24, 2026 19:57
…elayed-jobs query

- Remove module-level OAuth consumer cache and resetGarminConnectTestCaches
  export; use instance-level caching with type guard + validation for S3
  OAuth consumer JSON (fixes no-exports-for-testability violation)
- Remove explicit getDelayed(0, 49) limit so delayed-job dedup works
  for users with >50 pending delayed jobs
- Clean up imports and afterEach/beforeEach in tests
@Asherlc
Asherlc merged commit 254dbe4 into main Jun 25, 2026
71 checks passed
@Asherlc
Asherlc deleted the Asherlc/garmin-100-rate-limit branch June 25, 2026 04:23
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.

2 participants