You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为Moralis Speedy Nodes实现请求限流?异步场景下计数器方案失效的解决建议

Fixing Async Rate Limiting for Moralis Speedy Nodes

Hey there, let's work through why your current rate limiting approach isn't holding up for async requests, and fix it properly.

First, let's break down the clear issues in your existing code:

  • Syntax & Logic Bugs: The line if ((rate = 0)) is an assignment, not a comparison—so it will never evaluate to true, meaning time never gets initialized. Later, Date.now() - time will throw an error because time is undefined. Also, you set the reset window to 6000ms (6 seconds) instead of 60000ms (1 minute), which is way shorter than your intended limit.
  • Race Conditions: Since your requests are asynchronous, multiple calls to rateLimit() can run at the exact same time. When this happens, multiple functions might read the same rate value, increment it, and write it back—resulting in undercounting (e.g., two requests both increment from 5 to 6 instead of 5→6→7), which completely bypasses your limit.

Solution 1: Async-Safe Fixed Window Counter

To handle async concurrency, we need to ensure only one request can modify the counter at a time. We can use a mutex (mutual exclusion lock) to enforce this, along with proper window reset logic.

First, install the async-mutex package with npm install async-mutex, then use this implementation:

const { Mutex } = require('async-mutex');

// Configure your rate limits
const MAX_REQUESTS = 1450;
const WINDOW_MS = 60 * 1000; // 1 minute

let requestCount = 0;
let windowStart = Date.now();
const mutex = new Mutex();

async function rateLimit() {
  const release = await mutex.acquire();
  try {
    const now = Date.now();
    
    // Reset counter if the window has passed
    if (now - windowStart > WINDOW_MS) {
      requestCount = 0;
      windowStart = now;
    }
    
    if (requestCount < MAX_REQUESTS) {
      requestCount++;
      return true;
    } else {
      console.log("Rate limit reached: Too many requests in the last minute");
      return false;
    }
  } finally {
    release(); // Always release the lock, even if there's an error
  }
}

Solution 2: Token Bucket Algorithm (Better for Async Bursts)

If you expect occasional bursts of requests (but still want to stay under the 1500/min limit), the token bucket algorithm is more flexible. It allows short bursts as long as the average rate stays within the limit:

const { Mutex } = require('async-mutex');

const MAX_TOKENS = 1450;
const REFILL_RATE = MAX_TOKENS / (60 * 1000); // Tokens added per millisecond

let availableTokens = MAX_TOKENS;
let lastRefillTime = Date.now();
const mutex = new Mutex();

async function rateLimit() {
  const release = await mutex.acquire();
  try {
    const now = Date.now();
    const timePassed = now - lastRefillTime;
    
    // Refill tokens based on time passed
    availableTokens += timePassed * REFILL_RATE;
    // Don't let tokens exceed the maximum
    availableTokens = Math.min(availableTokens, MAX_TOKENS);
    lastRefillTime = now;
    
    if (availableTokens >= 1) {
      availableTokens--;
      return true;
    } else {
      console.log("Rate limit reached: No available tokens");
      return false;
    }
  } finally {
    release();
  }
}

How to Use These in Your Async Requests

Wrap your Moralis requests with the rate limiter, and add simple retry logic to avoid dropping requests when the limit is hit:

async function makeMoralisRequest() {
  const canProceed = await rateLimit();
  if (!canProceed) {
    // Wait 1 second then retry (you can adjust this to use exponential backoff too)
    await new Promise(resolve => setTimeout(resolve, 1000));
    return makeMoralisRequest();
  }
  
  // Your actual async request here
  try {
    const response = await fetch('YOUR_MORALIS_SPEEDY_NODE_URL', { /* request options */ });
    return response.json();
  } catch (err) {
    console.error("Request failed:", err);
    throw err;
  }
}

Key Notes

  • Mutex is Non-Negotiable: Without the mutex, concurrent async calls will still cause race conditions on the counter/token values.
  • Retry Logic: Adding a delay and retry ensures you don't lose requests when the limit is hit—just queue them until the window resets or tokens are refilled.
  • Safety Margin: Using 1450 instead of 1500 is smart, as it accounts for small timing inaccuracies that might push you over the hard limit.

内容的提问来源于stack exchange,提问作者Bora Varol

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 16:37:44