مدیریت خطا در API مالی و Rate Limit؛ الگوهایی که سیستم را سرپا نگه میدارد
مدیریت خطا در API مالی: معنی 401، 403، 429 و 5xx، تلاش مجدد با تأخیر افزایشی و Jitter، Circuit Breaker، نمایش آخرین نرخ معتبر و پایش؛ با کد پایتون و جاوااسکریپت.

- خطاها دو دستهاند: دائمی (401، 403، 422) که تلاش مجدد ندارند و موقت (429، 5xx، Timeout) که با تأخیر دوباره امتحان میشوند.
- برای 429 تا زمان `meta.reset_at` صبر کنید؛ تلاش مکرر فقط وضعیت را بدتر میکند.
- در هیچ خطایی صفحه نباید خالی شود: آخرین نرخ معتبر را با زمانش نشان دهید و قدیمی بودنش را اعلام کنید.
کد اتصال به API در روزهای عادی همیشه کار میکند. محک واقعی، روزی است که اینترنت سرور قطع و وصل میشود، سهمیه تمام شده یا کلید به اشتباه باطل شده است؛ و این روزها معمولاً با روزهای پرنوسان بازار همزماناند، یعنی وقتی کاربران بیشترین نیاز را به عدد دارند. در این مقاله مدیریت خطا در API مالی را با الگوهایی که در سیستمهای واقعی جواب دادهاند مرور میکنیم.
meta.reset_at صبر کنید. برای 5xx و Timeout حداکثر ۳ بار با تأخیر افزایشی (۱، ۲، ۴ ثانیه + کمی تصادفی) تلاش کنید. در همهٔ حالتها آخرین نرخ معتبر را با برچسب زمان نشان دهید.این مقاله بخشی از راهنمای کامل API قیمت ارز و طلا است.
کدهای خطا و معنی هر کدام
| کد | معنی در EZRate | دائمی یا موقت | کار درست |
|---|---|---|---|
400 / 422 | پارامتر نامعتبر (مثلاً نماد اشتباه یا quote ناشناخته) | دائمی | درخواست را اصلاح کنید؛ پیام خطا فیلد مشکلدار را میگوید |
401 invalid_api_key | کلید نیامده، اشتباه است یا باطل شده | دائمی | توقف و هشدار به تیم |
403 forbidden | IP یا دامنهٔ درخواست در فهرست مجاز کلید نیست | دائمی | تنظیم محدودیت کلید در پنل |
404 | نماد یا مسیر وجود ندارد | دائمی | فهرست نمادها را از /assets بخوانید |
429 rate_limited | سهمیهٔ روزانه یا ماهانه تمام شده | موقت تا زمان مشخص | صبر تا meta.reset_at |
5xx | خطای موقت سرور | موقت | تلاش مجدد با تأخیر |
| Timeout یا خطای شبکه | پاسخ نرسید | موقت | تلاش مجدد با تأخیر |
الگوی ۱: تلاش مجدد با تأخیر افزایشی و Jitter
اگر هزار کلاینت همزمان خطا بگیرند و همه دقیقاً بعد از یک ثانیه دوباره تلاش کنند، موج دوم از موج اول بزرگتر است. تأخیر افزایشی (۱، ۲، ۴ ثانیه) بههمراه کمی تصادفیسازی (Jitter) این موجها را پخش میکند:
import random, time, requests
TRANSIENT = {500, 502, 503, 504}
def get_with_retry(url, headers, params=None, tries=3):
for i in range(tries):
try:
r = requests.get(url, headers=headers, params=params, timeout=8)
except (requests.Timeout, requests.ConnectionError):
r = None
if r is not None and r.status_code not in TRANSIENT:
return r # موفق یا خطای دائمی/429: تصمیم با فراخواننده
time.sleep((2 ** i) + random.uniform(0, 0.5)) # 1s، 2s، 4s + jitter
raise RuntimeError("API unavailable after retries")الگوی ۲: مدیریت 429 و پایش سهمیه
وقتی سهمیه تمام میشود، پاسخ 429 در meta.reset_at زمان باز شدن دوباره را میگوید. تا آن زمان درخواست نفرستید. بهتر از آن، جلوی رسیدن به این وضعیت را بگیرید: مسیر GET /usage مصرف امروز و این ماه را میدهد و از سهمیه کم نمیشود. یک بررسی ساعتی کافی است تا قبل از تمام شدن سهمیه هشدار بگیرید:
const u = await (await fetch("https://api.ezrate.me/v1/usage", {
headers: { "X-API-Key": process.env.EZRATE_KEY } })).json()
console.log(JSON.stringify(u.data)) // مصرف و سقف امروز و این ماه
// اگر مصرف امروز از ۸۰٪ سقف گذشت، به تیم هشدار بدهیداگر سهمیه مرتب تمام میشود، قبل از ارتقای پلن ببینید کش درست کار میکند یا نه. در بیشتر موارد مشکل این است که هر بازدید صفحه یک درخواست جدید میسازد. راه حل در کش کردن API قیمت ارز با Redis آمده است.
الگوی ۳: Circuit Breaker
وقتی API چند بار پشت سر هم خطا داد، ادامهٔ تلاش در هر درخواست فقط زمان پاسخ سایت شما را بالا میبرد. Circuit Breaker مثل فیوز برق عمل میکند: بعد از چند خطای پیاپی، برای مدتی کوتاه اصلاً درخواست نمیفرستد و مستقیم از کش جواب میدهد؛ سپس یک درخواست آزمایشی میفرستد و اگر موفق بود، به حالت عادی برمیگردد:
class Breaker {
constructor(limit = 3, coolMs = 60_000) { Object.assign(this, { limit, coolMs, fails: 0, openUntil: 0 }) }
async call(fn, fallback) {
if (Date.now() < this.openUntil) return fallback() // باز: فقط کش
try {
const v = await fn()
this.fails = 0
return v
} catch (e) {
if (++this.fails >= this.limit) this.openUntil = Date.now() + this.coolMs
return fallback()
}
}
}
const breaker = new Breaker()
const rates = await breaker.call(fetchRatesFromApi, () => readLastGoodRates())
الگوی ۴: آخرین مقدار معتبر و صداقت با کاربر
در سیستمهای مالی، نشان دادن عدد قدیمی بدون اعلام آن، از نشان ندادن عدد بدتر است. هر جا آخرین مقدار معتبر را نمایش میدهید، زمانش را هم بگویید و اگر از حدی قدیمیتر است، آن را متمایز کنید:
| عمر نرخ | نمایش پیشنهادی |
|---|---|
| کمتر از ۵ دقیقه | عادی، با ساعت بهروزرسانی |
| ۵ تا ۶۰ دقیقه | عدد با رنگ کمرنگتر و عبارت «آخرین بهروزرسانی: …» |
| بیشتر از یک ساعت | هشدار صریح «نرخها موقتاً بهروز نمیشوند» و توقف هر محاسبهٔ خودکار مالی |
الگوی ۵: Timeout را خودتان تعیین کنید
بدون timeout، یک درخواست معلق میتواند پروسهٔ PHP یا Node.js شما را دقیقهها نگه دارد و در ساعت شلوغ همهٔ ظرفیت سرور را بگیرد. برای درخواست نرخ، ۵ تا ۸ ثانیه کافی است. در پایتون با timeout=، در Node.js با AbortSignal.timeout() و در لاراول با ->timeout().
پایش و هشدار
- تعداد خطا به تفکیک کد را ثبت کنید؛ افزایش ناگهانی 401 یعنی کلید عوض شده یا باطل شده است.
- سن آخرین نرخ معتبر را پایش کنید؛ اگر از ۱۰ دقیقه گذشت، هشدار بفرستید.
- وضعیت Circuit Breaker را در داشبورد نشان دهید.
- نسخهٔ انگلیسی با تمرکز بر SLA و Failover در Financial API Failover Strategies آمده است.
نرخهای لحظهای مرتبط با این مطلب: قیمت دلار، قیمت طلای ۱۸ عیار، قیمت سکه امامی.

نظرات (۰)
نظرها پس از تأیید نمایش داده میشوند؛ برای ارسال، ورود به حساب لازم است.


