Skip to content

Bug: Hardcoded Concurrency Limits May Cause API Rate Limiting #375

Description

@TanCodeX

Summary

The leaderboard synchronization scripts use Promise.all with a fixed batch size (e.g., 20 concurrent requests) to process API calls. This hardcoded concurrency limit does not adapt to varying API rate limits or server conditions, increasing the likelihood of request throttling, failures, or degraded performance.

Affected Files

  • scripts/sync-leaderboard.js
  • Any other synchronization scripts using fixed-size Promise.all batches

Description

The synchronization logic processes API requests in batches with a hardcoded concurrency limit, for example:

const BATCH_SIZE = 20;

// Process each batch
await Promise.all(batch.map(syncUser));

While batching reduces the number of simultaneous requests, the fixed concurrency level is inflexible:

  • May exceed the LeetCode API's rate limits.
  • Does not adapt to changes in network conditions or API capacity.
  • A single rate-limited request can cause failures for the entire batch.
  • Lacks retry and exponential backoff mechanisms for transient errors.

Steps to Reproduce

  1. Run the synchronization script against a large number of users.
  2. Observe concurrent API requests being sent in fixed-size batches.
  3. Simulate or encounter API rate limiting (e.g., HTTP 429 responses).
  4. Notice request failures or interrupted synchronization due to lack of adaptive concurrency control.

Expected Behavior

The synchronization process should dynamically control concurrency, gracefully handle rate limits, and retry transient failures using backoff strategies.

Actual Behavior

The script relies on a fixed concurrency limit, which may overwhelm the external API or result in unnecessary request failures under varying conditions.

Performance Impact

  • Increased likelihood of API rate limiting.
  • Higher failure rates during synchronization.
  • Reduced reliability when processing large datasets.
  • Difficult to tune across different environments or API policies.

Recommendation

Replace the manual batching approach with a concurrency control library such as p-limit, p-queue, or async.queue. These libraries provide configurable concurrency limits and can be combined with retry and exponential backoff logic to improve resilience.

Example using p-limit:

import pLimit from 'p-limit';

const limit = pLimit(10);

await Promise.all(
  users.map(user =>
    limit(() => syncUser(user))
  )
);

For additional robustness:

  • Implement exponential backoff for retryable errors (e.g., HTTP 429 or 5xx responses).
  • Respect Retry-After headers when provided by the API.
  • Make concurrency configurable via environment variables instead of hardcoding values.
  • Log and retry transient failures without aborting the entire synchronization process.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions