سقفها و محدودیت نرخ
هر عددی که سرور به آن پایبند است، و اینکه کدامیک را میشود در زمان اجرا از خود سرور پرسید.
هر عددی که در این صفحه هست از همان کدی میآید که اعمالش میکند. هرجا یک سقف بهجای رد کردن، داده شما را کوتاه میکند، همانجا صریح گفته شده است، چون کوتاه شدن بیصدا همان خرابیای است که ماهها بعد از یک گزارش بیمعنی میفهمید.
سقفها را از سرور بخوانید
مسیر GET /v1/capabilities پنج تا از این عددها را در زمان اجرا منتشر میکند. یک واحد بودجه خرج دارد و هیچ مجوزی نمیخواهد.
curl -s https://api.segmentic.net/v1/capabilities \
-H "Authorization: Bearer sk_seg_..."
{
"version": "v1",
"features": {
"segments": true,
"campaigns": true,
"analytics": true,
"transactional": true,
"export": true,
"import": true,
"journeys": true,
"ingest": true,
"async_exports": true,
"campaign_approval": true
},
"limits": {
"max_page_size": 100,
"max_preview_rows": 100,
"max_batch_size": 500,
"estimate_sample": 100,
"query_timeout_sec": 30
}
}
مقدارهای max_page_size و max_batch_size را از همینجا بخوانید، نه اینکه ۱۰۰ و ۵۰۰ را در کد بنویسید. هر پرچم در features میگوید همین استقرار در عمل چه چیزی سرو میکند، پس نصب خودمیزبانی که موتور تحلیل ندارد "analytics": false میدهد و کلاینت شما میتواند موقع بالا آمدن شکست بخورد بهجای وسط کار.
چهار هشدار درباره این پاسخ، هر چهار چیزی که خواننده فرض میگیرد و نباید بگیرد.
- مقدارهای
max_preview_rowsوestimate_sampleروی میزبان مدیریتی هیچچیز را محدود نمیکنند. مال دو نقطه در پنلاند که اینجا ثبت نشدهاند. نادیده بگیریدشان. - مقدار
query_timeout_secبرابر ۳۰ است و مهلت خواندنها و نوشتنها وPOST /v1/audiences/countاست. مهلتی که دو مسیر گزارش استفاده میکنند نیست، آن ۴۵ ثانیه است. مهلتها را ببینید. - کلیدهای
ingestوimportیک بولیناند با دو اسم، همانی کهPOST /v1/eventsرا روشن میکند. - پرچم
exportهیچ مسیری را روی این میزبان کنترل نمیکند. دو مسیر خروجی راasync_exportsروشن و خاموش میکند. حسابی که"export": falseمیبیند ممکن است هر دو مسیر خروجی را داشته باشد، و برعکس. برای خروجی بهasync_exportsنگاه کنید.
بقیه چیزهای این صفحه را ناچارید در کد بنویسید، چون جایی برای خواندنشان نیست. نه GET /v1/reports/limits وجود دارد و نه نقطهای که سقف رویداد حساب شما یا مصرف فعلیاش را بگوید.
سقفهای ورود داده
اینها روی هر دو در اعمال میشوند: میزبان ورود داده، و POST /v1/events روی میزبان مدیریتی.
| سقف | مقدار | روی چه | وقتی رد شود |
|---|---|---|---|
| طول نام رویداد | 128 bytes | فیلد event در track | رد میکند، event_name_too_long |
| طول شناسه | 256 bytes | user_id و anonymous_id و message_id | رد میکند، id_too_long |
| طول شناسه نشست | 256 bytes | context.session_id | بیصدا کوتاه میکند |
| شناسه قبلی | بدون سقف | previous_id در alias | فقط وجودش بررسی میشود، هرگز طولش |
| کلید ویژگی | 128 bytes | هر کلید، بعد از نرمالسازی | بیصدا کوتاه میکند |
| مقدار ویژگی | 8192 bytes | هر مقدار رشتهای | بیصدا کوتاه میکند |
| تعداد ویژگی در رویداد | 256 | properties | ۲۵۶ تای اول را نگه میدارد، too_many_properties |
| تعداد ویژگی در identify | 256 | traits | ۲۵۶ تای اول را نگه میدارد، too_many_traits |
| تعداد رویداد در دسته | 500 | POST /v1/batch و POST /v1/events | رد میکند، batch_too_large |
| بدنه درخواست | 5 MiB | کل درخواست روی میزبان ورود داده | رد میکند، ۴۱۳ |
| نشانی صفحه | 2048 bytes | context.page.url و .path و .referrer | بیصدا کوتاه میکند |
| بدنه وبهوک | 1 MiB | POST /v1/hooks/{source}/{token} | رد میکند |
| گزارش برگشتی | 1 MiB | POST /v1/bounce/{local} | رد میکند، ۴۱۳ |
فقط یکی از اینها کلید پیکربندی دارد. کلید MAX_BODY_BYTES سقف بدنه را میگذارد و پیشفرضش 5242880 است. بقیه در کد کامپایل شدهاند، پس نصب خودمیزبان هم نمیتواند بالاترشان ببرد.
ترتیب مهم است. رد کردن قبل از کوتاه کردن رخ میدهد و کوتاه کردن قبل از ذخیره، پس رویدادی با user_id سیصدبایتی کامل رد میشود، نه اینکه با شناسه کوتاهشده ذخیره شود.
سقفهای بیصدا
هر فیلد دیگری داخل context بدون هیچ هشدار و هیچ خطایی کوتاه میشود. اینجا آورده شدهاند چون راه دیگر فهمیدنشان این است که یک سگمنت آدمهایی را که انتظار داشتید نگیرد.
| بایت | فیلدها |
|---|---|
8 | ویژگی currency، با حروف بزرگ |
16 | context.device.push_provider |
32 | context.locale و context.device.type و context.os.name و context.os.version و context.library.version، و نسخه مرورگر که از User-Agent درمیآید |
64 | context.timezone و context.ip و context.app.version و context.device.manufacturer و context.network.carrier و context.library.name و context.location.country و context.location.region و context.location.city و context.campaign.variant_id، و نام مرورگر و سازنده دستگاه که از User-Agent درمیآیند |
128 | context.device.model و context.campaign.token و هر پنج فیلد utm: source و medium و name و term و content |
256 | context.session_id و context.campaign.message_id |
512 | context.page.title، و خود هدر User-Agent |
کشور و استان و شهر و عنوان صفحه و هر نام رویداد پیش از کوتاه شدن از نرمالسازی فارسی هم رد میشوند، پس ی و ک عربی به ی و ک فارسی تبدیل میشوند. همین است که میگذارد سگمنت روی city = تهران مشتریهایی را بگیرد که اپهایشان سر املا با هم اختلاف دارند.
اگر مقداری برای یک سگمنت یا یک گزارش مهم است، خودتان داخل این کرانهها نگهش دارید.
پنجره زمانی رویداد
هر رویداد timestamp خودش را دارد. اینکه چقدر میتواند به عقب برسد، نگهداشت رویداد حساب خودتان است، نه یک ثابت.
| تنظیم | مقدار | رفتار |
|---|---|---|
| پنجره پیشفرض گذشته | ۳۰ روز | کف. حسابی که نگهداشتش ۳۰ روز است هم همان ۳۰ روز کامل را میگیرد |
| پنجره آینده | ۱ ساعت | جلوتر از این، به زمان دریافت چسبانده و timestamp_in_future هشدار داده میشود |
| نگهداشت روی «برای همیشه» | ۳۶۵۰ روز | ده سال، که با وجود اسمش متناهی است تا زمان ۱۹۷۰ از یک ساعت خراب همچنان رد شود. پنجره پیشفرض حسابی است که هرگز صفحه نگهداشت را باز نکرده |
در ورود داده زنده، زمانی قدیمیتر از پنجره به لبه پنجره چسبانده میشود و رویداد با هشدار timestamp_too_old پذیرفته میشود. رد نمیشود.
این تنها رفتار پلتفرم است که بیشترین احتمال را دارد یک هفته از شما بگیرد. پیشتر همان ۳۰ روز کل پنجره بود، هرچه نگهداشت شما میگفت، و نشانهاش نامرئی بود: حسابی که دو سال تاریخچه را مهاجرت میداد، هر رویداد قدیمیتر از سی روز را بیصدا درست روی «سی روز پیش» میدید، پذیرفتهشده با یک هشدار و کد ۲۰۰. هیچچیز شکست نخورد. داده فقط غلط بود، همهاش روی یک زمان تلنبار، و اولین نشانهاش ماهها بعد قیفی بود که هیچ معنی نمیداد. حالا پنجره از سیاست نگهداشت شما میآید، همان چیزی که این چسباندن همیشه ادعا میکرد اعمالش میکند.
خواندن نگهداشت یک دقیقه کش میشود و وقتی خوانده نشود نرم به ۳۰ روز برمیگردد.
در backfill همین شرط بهجای چسباندن رد میکند، با timestamp_too_old، چون در backfill جابهجا کردن یک زمان بدتر از رد کردنش است. سطر backfill که هیچ زمانی نداشته باشد هم رد میشود.
پنجرهای که از نگهداشت میآید فقط روی میزبان ورود داده اعمال میشود. مسیر POST /v1/events روی میزبان مدیریتی سیاست حساب شما را نمیخواند و همیشه همان پیشفرض ۳۰ روز را میگیرد، چون گزینههایش را بدون MaxPast میسازد. هر رویداد قدیمیتر از سی روز که از این در بفرستید بیصدا روی «سی روز پیش» مینشیند و ۲۰۰ میگیرد، و پاسخ هیچ هشداری هم ندارد چون این مسیر هشدارها را دور میریزد. تاریخچه را هرگز از اینجا مهاجرت ندهید. وارد کردن رویداد در پنل بهجای چسباندن رد میکند، و رد کردن همان چیزی است که مهاجرت لازم دارد.
نگهداشت پنجره ورود است، نه عمر داده
این دو عدد یکی نیستند و اشتباه گرفتنشان گران است. سیاست نگهداشت تا ۳۶۵۰ روز اعتبارسنجی میشود و کف غیرصفرش ۳۰ روز است. ولی جدول رویدادها در کلیکهاوس یک TTL ثابت چهارصد روزه روی event_time دارد که به سیاست حساب کار ندارد و هر سطری را میاندازد.
پس نگهداشت ده ساله را میشود ذخیره کرد و در عمل هیچ رویدادی بیشتر از چهارصد روز از زمان خودش زنده نمیماند. سیاست فقط میگوید چه زمانی را موقع ورود میپذیریم و کی زودتر از چهارصد روز پاک میشود؛ بالا بردنش عمر داده را زیاد نمیکند.
اگر تاریخچه بلندتر از چهارصد روز لازم دارید، پیش از رسیدن به آن مرز خودتان خروجی بگیرید. جای دیگری برای گرفتنش نیست.
سقفهای میزبان مدیریتی
| سقف | مقدار | روی چه |
|---|---|---|
| بدنه درخواست | 8 MiB | بیشتر مسیرها |
| بدنه درخواست | 256 KiB | POST /v1/messages |
| بدنه درخواست | 1 MiB | POST /v1/audiences/validate و POST /v1/audiences/count و دو مسیر گزارش |
| بیشترین اندازه صفحه | 100 | هر مسیر فهرست |
| اندازه صفحه پیشفرض | 25 | هر مسیر فهرست |
| نوع خروجی | events و messages و profiles و segment | POST /v1/exports |
| قالب خروجی | پیشفرض ndjson، تنها جایگزین csv | POST /v1/exports |
| عمر فایل خروجی | ۷ روز | در بدنه ۲۰۲ با expires_after_hours: 168 منتشر میشود |
سه سقف مختلف بدنه اشتباهی نیست که کسی درستش کرده باشد. مسیر POST /v1/messages سهمش 256 KiB است چون payload تراکنشی یک شناسه قالب است و چند متغیر، و آن چهار مسیری که هندلر پنل را قرض میگیرند همان 1 MiB هندلر را میگیرند.
صفحهبندی
پارامتر limit بریده میشود، هرگز رد نمیشود. مقدار limit=500 به شما ۱۰۰ میدهد. مقدارهای limit=0 و limit=banana هر دو ۲۵ میدهند. خطایی نمیگیرید که سقف را بگوید؛ آن را از GET /v1/capabilities بخوانید.
کرسر یک رشته مبهم base64url است. کرسری که دیکد نشود بیصدا ابتدای فهرست فرض میشود، نه خطا، پس کلاینتی که کرسرش را خراب کند تا ابد روی صفحه یک میچرخد بهجای اینکه شکست بخورد. شناسههایی را که میگیرید با آنچه دارید مقایسه کنید.
مسیر GET /v1/exports پارامتر limit را میگیرد ولی هرگز کرسر برنمیگرداند. پاسخش {"data":[...],"has_more":false} است و has_more حتی وقتی کار بیشتری هست هم false است. هیچ راهی برای رفتن به صفحه بعد نیست. بیشترین مقدار یعنی ۱۰۰ را بخواهید و همان را کل فهرست بدانید.
مسیرهای GET /v1/segments و GET /v1/campaigns با شکل خود هندلر پنل جواب میدهند، یعنی {"segments":[...]} و {"campaigns":[...]}، نه با پاکت صفحهبندی. شکل data و next_cursor فقط روی GET /v1/exports ظاهر میشود.
هر دوی آن دو مسیر در خود SQL روی ۲۰۰ سطر بریده شدهاند: دویست سگمنتی که تازهتر از همه بهروز شدهاند، و دویست کمپینی که تازهتر از همه بهروز شدهاند. سقف بیصداست. نه has_more هست، نه next_cursor، نه شمارشی، نه هشداری، و ?limit= و ?cursor= هم اینجا خوانده نمیشوند. حسابی که ۲۵۰ سگمنت دارد دویستتا را میبیند و روی هیچ سطحی راهی به آن ۵۰ تای دیگر ندارد، حتی در پنل. اگر کتابخانه شما از این عدد بگذرد، فهرست خودتان را جای دیگری نگه دارید و شناسه را مستقیم به GET /v1/segments/{id} بدهید.
سقفهای گزارش
برای POST /v1/reports/funnel و POST /v1/reports/retention.
| سقف | مقدار | چه چیزی را میبندد |
|---|---|---|
| بازه زمانی | ۷۳۰ روز | گستردهترین پنجرهای که این دو گزارش اسکن میکنند. دو سال برای یک حساب بزرگ همین حالا صدها میلیارد سطر است |
| مراحل قیف | ۱۲ | برای هر مرحله یک شرط ساخته میشود و آدم باید نتیجه را بخواند |
| دورههای ماندگاری | ۶۰ | تعداد ستونهای جدولی که کسی باید بخواند. اگر صفر یا کمتر بفرستید ۳۰ میشود |
| فیلتر در هر گزارش | ۱۰ | |
| طول کلید ویژگی | ۱۲۸ | |
| طول نام رویداد | ۲۵۶ | |
| طول مقدار ویژگی | ۵۱۲ | |
| عمق مسیر | ۸ | گزارش مسیرها، که روی این میزبان نیست |
| سطرهای مسیر | ۱۰۰ | گزارش مسیرها، که روی این میزبان نیست |
هر کدام از این خرابیها با یک کد برمیگردد، invalid_report. پشت آن یک کد سیزده خطای اعتبارسنجی متمایز هست و هیچ راه برنامهای برای جدا کردنشان. نه تای آنها جمله فارسی کاتالوگ را در error میگذارند؛ چهار سطر پایینی این جدول، یعنی طول نام رویداد و تعداد فیلتر و طول کلید ویژگی و طول مقدار ویژگی، از شاخه پیشفرض رد میشوند و متن انگلیسی خود خطا را میآورند، مثل analytics: too many filters. اگر لازم دارید روی رشته تطبیق بدهید، و بپذیرید که نه رشته قرارداد است و نه زبانش.
گزارش مسیرها وجود دارد ولی فقط روی mux پنل ثبت شده است. با کلید API دسترسپذیر نیست.
سقفهای مخاطب و سگمنت
اینها تعریفی را میبندند که به POST /v1/audiences/validate و POST /v1/audiences/count و POST /v1/segments و PUT /v1/segments/{id} میفرستید.
| سقف | مقدار | متن خطا |
|---|---|---|
| عمق تودرتویی | ۸ | segment: nesting too deep |
| تعداد شرط | ۲۰۰ | segment: too many conditions |
| مقدار در یک فهرست | ۱۰۰۰ | segment: list has too many values |
| طول کلید ویژگی | ۱۲۸ |
شمارش شرطها گزارههای روی ویژگی رویداد را هم شامل میشود، نه فقط گرههای درخت منطقی، پس تعریفی که روی صفحه بیست شرط به نظر میرسد میتواند اینجا خیلی بیشتر از صد باشد. هر چهارتا با کد filter_invalid و وضعیت ۴۲۲ و جمله خود کامپایلر بهعنوان متن بیرون میآیند.
قبل از ذخیره اعتبارسنجی کنید. مسیر POST /v1/audiences/validate تعریف را بدون دست زدن به پایگاه داده کامپایل میکند، یک واحد بودجه خرج دارد، و بهجای ۲۰۰ با valid: false که پنل میدهد، ۴۲۲ میدهد.
سقفهای ارسال تراکنشی
| سقف | مقدار | کلید پیکربندی |
|---|---|---|
| متغیر در هر پیام | ۴۰ | ندارد |
| قالب کلید idempotency | ^[A-Za-z0-9._:-]{8,200}$ | ندارد |
| عمر کلید idempotency | ۷ روز | API_IDEMPOTENCY_RETENTION، پیشفرض 168h |
| مهلت رزرو مانده | ۱ دقیقه | API_STALE_RESERVATION |
| بدنه درخواست | 256 KiB | ندارد |
قالب کلید بهعمد سختگیر است. کلید بخشی از شناسه پیام میشود، و شناسه پیام در دفتر و شمارنده تعداد و مرجع خود ارائهدهنده نوشته میشود، پس کلیدی که خط جدید یا گیومه داشته باشد راه درازی میرفت تا جایی بالاخره ردش کند. شناسه پیام مشتق است نه ساختهشده: t<tenant_id>.<کلید شما>، پس یک کلید تا آخر خط همان شناسه را میسازد.
فیلد category وقتی نفرستیدش transactional میشود. مقدار marketing با ۴۰۰ مستقیم رد میشود. این نقطه سقف تعداد و ساعت سکوت را دور میزند، پس قبول کردن پیام بازاریابی اینجا یعنی به شما یک راه مستند برای دور زدن قواعد ارسال خودتان بدهیم، و اولین باری که مهم میشد یک پیامک تبلیغاتی ساعت سه بامداد به کل فهرست بود.
بودجه درخواست
هر مسیر میزبان مدیریتی بهجز GET /v1/status با واحد وزندار سنجیده میشود. «درخواست در دقیقه» واحد غلطی است برای سطحی که یک فراخوانیاش یک ساختار را میخواند و فراخوانی بعدیاش یک انبار داده را اسکن میکند.
| کلاس | وزن | یعنی چه |
|---|---|---|
| ساده | 1 | چیزی نمیخواند، یا یک سطر با کلید اصلی میخواند |
| کوئری | 5 | یک کوئری کراندار روی انبار داده |
| سنگین | 25 | اسکنی که هزینهاش با تاریخچه شما بزرگ میشود |
هزینه هر مسیر:
| مسیر | هزینه | مجوز |
|---|---|---|
GET /v1/whoami | 1 | ندارد |
GET /v1/capabilities | 1 | ندارد |
GET /v1/schema/events | 5 | event.read |
GET /v1/schema/traits | 5 | event.read |
POST /v1/audiences/validate | 1 | segment.read |
POST /v1/audiences/count | 25 | segment.read |
GET /v1/segments | 1 | segment.read |
GET /v1/segments/{id} | 1 | segment.read |
POST /v1/segments | 1 | segment.write |
PUT /v1/segments/{id} | 1 | segment.write |
DELETE /v1/segments/{id} | 1 | segment.delete |
GET /v1/campaigns | 1 | campaign.read |
GET /v1/campaigns/{id} | 5 | campaign.read |
POST /v1/campaigns | 1 | campaign.write |
PUT /v1/campaigns/{id}/recurrence | 1 | campaign.send |
DELETE /v1/campaigns/{id}/recurrence | 1 | campaign.send |
POST /v1/campaigns/{id}/send | 1 | campaign.send |
POST /v1/campaigns/{id}/submit | 1 | campaign.write |
POST /v1/events | 5 | profile.write |
GET /v1/exports | 1 | data.export |
POST /v1/exports | 25 | data.export |
POST /v1/reports/funnel | 25 | analytics.read |
POST /v1/reports/retention | 25 | analytics.read |
POST /v1/messages | 1 | campaign.send |
ساز و کارش:
| ویژگی | مقدار |
|---|---|
| سهمیه پیشفرض | 600 واحد در دقیقه، از PUBLIC_API_BUDGET_PER_MINUTE |
| الگوریتم | پنجره ثابت، یک رفت و برگشت به ردیس |
| پنجره | یک دقیقه ساعت دیواری، نه دقیقه غلتان |
| دامنه | به ازای هر کلید API، نه هر حساب |
| جهت خرابی | بسته شکست میخورد. ردیس در دسترس نباشد یعنی ۵۰۳ با budget_unavailable |
| زمان برداشت | قبل از اجرای هندلر، و حتی وقتی هندلر بعدش شکست بخورد هم برداشته میشود |
۶۰۰ واحد کموبیش یعنی دو دوجین گزارش سنگین در دقیقه، یا ششصد فراخوانی ارزان. دقیقش: ۲۴ فراخوانی سنگین میگذرد و بیستوپنجمی رد میشود.
بودجه برخلاف محدودیت نرخ پایینتر، به کلید API کلید خورده است نه به حساب، و این عمدی است. شما یک کلید باریک به یک ایجنت میدهید و کلید یکپارچهسازی خودتان را جدا نگه میدارید، و ایجنتی که در حلقه افتاده نباید بتواند بودجهای را که خط سفارش شما به آن وابسته است تمام کند. MCP را ببینید.
هزینه POST /v1/messages برابر ۱ است، که برای فراخوانیای که میتواند به گوشی یک آدم پیام بفرستد غلط به نظر میرسد. غلط نیست: هزینه آن فراخوانی از نظر کوئری ناچیز است و از نظر پیامد عظیم، و چیزی که قرار بود بندش بزند بودجه گیرنده است، که وجود ندارد. آنچه سقف ندارد را ببینید.
روی بودجه هیچ هدر X-RateLimit-* وجود ندارد. نه روی پاسخهای رد و نه روی پاسخهای موفق. مسیر GET /v1/whoami هم بودجه باقیمانده را نمیگوید. نمیتوانید ببینید چقدر نزدیک شدهاید: یا خرج خودتان را از جدول بالا بشمارید، یا ۴۲۹ را مدیریت کنید.
تنها راه برگشت زمان است. کلید ردیس ۷۰ ثانیه بعد از اولین برداشت در آن پنجره منقضی میشود و سطل دقیقه با ساعت دیواری میچرخد. نه نقطهای برای صفر کردن هست، نه بازنویسی به ازای کلید، و نه راهی برای بالا بردن سهمیه جز عوض کردن متغیر محیطی و ریاستارت پروسه.
درخواست ردشده یک حساب قفلشده همچنان واحد بودجهاش را خرج میکند، چون بررسی قفل بعد از برداشت بودجه اجرا میشود.
محدودیت نرخ ارسال تراکنشی
ساز و کار دومی که بهکلی جداست. بهجای واحد هزینه، درخواست میشمارد، دامنهاش حساب است نه کلید، و در جهت مخالف شکست میخورد.
| ویژگی | مقدار |
|---|---|
| روی چه اعمال میشود | فقط POST /v1/messages و هیچچیز دیگر |
| الگوریتم | پنجره ثابت، با INCR ردیس |
| پنجره | یک دقیقه ساعت دیواری |
| دامنه | به ازای هر حساب. چرخاندن کلید سهمیه تازه نمیخرد |
| منبع سقف | فیلد api_rate_per_minute خود حساب شما، روی هر درخواست و بدون کش خوانده میشود |
| پیشفرض | API_RATE_PER_MINUTE، که با مقدار 0 منتشر شده است |
مقدار 0 یعنی | اندازهگیری بهکلی خاموش. این پیشفرض منتشرشده است |
| جهت خرابی | باز شکست میخورد. ردیس در دسترس نباشد یعنی فراخوانی رد میشود جلو |
بهعمد باز شکست میخورد، و دلیلش ترافیکی است که حمل میکند. این نقطه رسید سفارش و کد ورود میفرستد. رد کردن همهشان چون یک کش پایین است، خرابی ما را تبدیل میکند به شکست خوردن پرداخت مشتری شما. محدودیت نرخ هست که جلوی یکپارچهسازی در حال فرار را بگیرد، و آن مشکلی است که دیر رسیدن به آن میارزد.
چون پنجره ثابت است، یک فراخوان میتواند سر مرز دو پنجره، دو پنجره پیام بفرستد. برای سقفی که کارش متوقف کردن یک حلقه فراری است نه اندازهگیری تکتک درخواستها، این معامله درستی است.
وقتی سقفی تنظیم شده باشد، دو هدر روی هر پاسخ میآیند، حتی پاسخهای موفق، تا بتوانید قبل از رد شدن آهسته کنید.
HTTP/1.1 200 OK
X-RateLimit-Limit: 10
X-RateLimit-Remaining: 9
Content-Type: application/json; charset=utf-8
مقدار X-RateLimit-Remaining هرگز منفی نمیشود. هدر X-RateLimit-Reset و هدر X-RateLimit-Resource وجود ندارند. با پیشفرض منتشرشده که صفر است، هیچ هدری فرستاده نمیشود.
میزبان ورود داده هیچ محدودکننده نرخی ندارد. تنها کنترلهای حجمش سقف بدنه، سقف دسته و دروازه سهمیهاند.
سهمیه
سهمیه سقف پلن است که روی یک ماه جلالی شمرده میشود.
| سنجه | چه میشمارد |
|---|---|
events | هرچه کالکتور پذیرفته، از جمله تکراریهای زدودهشده |
profiles | بیشترین تعداد آدم شناساییشده در دوره، نه جمعشان |
messages.email و messages.sms و messages.push و messages.web و messages.inapp | ارسالها، یک سنجه برای هر کانال |
messages.messenger | بله و ایتا و روبیکا با هم در یک سنجه |
رویدادها فقط بعد از پذیرفته شدن سنجیده میشوند، پس payload ردشده صورتحساب نمیشود و تلاش دوباره تکراریزداییشده هم نمیشود. SDK ای که دوباره میفرستد برای ما یک جستوجوی ردیس خرج دارد، نه یک خط فاکتور که سرش با ما دعوا کنید. پیامها فقط روی ارسال موفق سنجیده میشوند.
پلن دو سقف سخت دارد، max_events و max_messages، که از سهمیه شامل جدا هستند. صفر یعنی بیسقف: مازاد صورتحساب میشود و همهچیز کار میکند. رد شدن از سهمیه شامل، پول خرج دارد و یک فاکتور است. رد شدن از سقف، شما را متوقف میکند و یک قطعی است.
فقط سقف رویداد اعمال میشود. هیچ مسیر کدی سنجه پیام را در برابر max_messages بررسی نمیکند، پس quota_message_cap هرگز رخ نمیدهد. این فیلد تعریف شده، اعتبارسنجی شده، روی فاکتور چاپ میشود، و هیچجا اعمال نمیشود.
وقتی به سقف برسید چه میشود:
- درخواست کامل با ۴۰۲ رد میشود، هرگز نیمبند پذیرفته نمیشود. پذیرش جزئی شما را ناتوان میگذاشت از اینکه بفهمید کدام رویدادها را دوباره بفرستید، و به هر حال از سقف رد شدهاید.
- بررسی یک بار برای کل دسته اجرا میشود، پیش از هر کار قلمبهقلم.
- هر SDK دستهای را که نگه داشته دور میریزد، چون هر سه هر ۴xx بهجز ۴۲۹ را دائمی میشمارند. آن رویدادها رفتهاند.
- تلاش دوباره تا کسی پول ندهد هیچچیز را عوض نمیکند.
حکم سهمیه ۱۵ ثانیه به ازای هر حساب کش میشود، پس میتوانید به اندازه هرچه در آن پنجره بفرستید از سقف بزنید بیرون. دروازه باز هم شکست میخورد: اگر خواندن اشتراک یا مصرف خطا بدهد، ترافیک پذیرفته میشود.
دوره یک ماه جلالی است نه میلادی، و روزهای داخلش به وقت محلی تهران شمرده میشوند. دوره درست همانجا تمام میشود که دوره بعد شروع میشود، پس هیچ لحظهای بین دو دوره نمیافتد.
اعلانها، که چیزی را رد نمیکنند، روی ۳۰۰ و ۱۵۰ و ۱۲۵ و ۱۰۰ و ۸۰ درصد سهمیه شامل رخ میدهند، هر ماه جلالی یک بار برای هر سنجه.
قفل نرم
یک کنترل مالی است، نه محدودیت نرخ.
| محرک | آستانه |
|---|---|
| فاکتور سررسیدگذشته | فاکتور صادرشدهای که دستکم ۷۵ روز از سررسیدش گذشته باشد. اعلام واریز خلعش میکند |
| مصرف | پروندهها یا رویدادها روی ۳۰۰ درصد سهمیه شامل یا بالاتر |
اول سررسید بررسی میشود. حکم ۶۰ ثانیه به ازای هر حساب کش میشود و روی هر مسیری که نتواند بخواند، باز شکست میخورد. عدد پروندهها تا یک ساعت عقب است، چون یک کار پسزمینه مینویسدش.
درست چهار مسیر میزبان مدیریتی را میبندد: GET /v1/exports و POST /v1/exports و POST /v1/reports/funnel و POST /v1/reports/retention.
بقیه بهعمد باز میمانند: ورود داده، ارسال تراکنشی، ساخت کمپین، ارسال کمپین، و نوشتن سگمنت. سوراخ در داده شما را بعدها نمیشود پر کرد و بدهی را بعدها میشود وصول کرد.
همین قفل همان دو خانواده را در پنل هم میبندد. قفلی که یک نوع اعتبارنامه رعایتش کند و نوع دیگر نکند قفل نیست، یک دور زدن است، و آن دور زدن فاصلهاش تا شما یک اسکریپت است.
مهلتها
| فراخوانی | سقف سمت سرور |
|---|---|
GET /v1/whoami و GET /v1/capabilities و GET /v1/status | هیچ کار پایگاه داده ندارند |
هر خواندن، هر نوشتن، POST /v1/audiences/count، POST /v1/messages | 30 s، مهلت کوئری |
POST /v1/reports/funnel و POST /v1/reports/retention | هندلر 45 s میدهد، ولی شنونده پاسخ را سر 30 s میبرد |
| هر فراخوانی روی میزبان مدیریتی | WriteTimeout 30 s، ReadTimeout 15 s، ReadHeaderTimeout 5 s |
| هر فراخوانی روی میزبان ورود داده | WriteTimeout 30 s، ReadTimeout 15 s، IdleTimeout 120 s |
سطر گزارشها یک تناقض واقعی است، نه اختلاف گردکردن. قیفی که بین ۳۰ و ۴۵ ثانیه طول بکشد را سرور HTTP میبرد، نه هندلر، پس بهجای یک خطای تمیز یک پاسخ ناقص میبینید. بازه زمانی یا تعداد مراحل را کم کنید.
مهلت ۳۵ ثانیه روی کلاینت هر سقفی که اینجا هست را پوشش میدهد. بالاتر رفتن چیزی به شما نمیدهد، چون شنونده به هر حال سر ۳۰ ثانیه اتصال را میبندد.
آنچه سقف ندارد
هرکدام از اینها سقفی است که خواننده انتظار دارد پیدا کند. هیچکدامشان وجود ندارد.
- سقفی روی تعداد نام رویداد یا کلید ویژگی متمایز نیست. مقدارهای
max_propertiesوmax_traitsیک payload را میبندند، نه اسکیمای شما را. میتوانید ده هزار نام رویداد متمایز بسازید و هیچچیز جلویتان را نمیگیرد. هیچچیز هم مفیدشان نمیکند. - سقف سطر روی خروجی نیست. مسیر
POST /v1/exportsسه فیلدkindوformatوspecمیگیرد، و نهmax_rowsدارد، نه سقف سمت سرور، و نهexpected_countروی کار. - محدودیت نرخ به ازای IP هیچجای محصول نیست. نه روی میزبان ورود داده و نه روی میزبان مدیریتی.
- بودجه گیرنده نیست. هیچچیز نمیشمارد که یک کلید در روز به چند نفر میتواند بفرستد، و برای همین
POST /v1/messagesیک واحد بودجه خرج دارد و با صد هزار فراخوانی میتواند به صد هزار گوشی برسد. خودتان بندش را بگذارید. - سقف پیام اعمال نمیشود. بالاتر گفته شد.
- نقطه import روی میزبان مدیریتی نیست. وارد کردن CSV قابلیت پنل است، با سقف ۵۰۰۰۰۰ سطر و ۶۴ مگابایت، و API ندارد.
- هدر
Accept-Languageخوانده نمیشود. هیچکدام از دو میزبان نمیخوانندش. متن سهمیه و قفل همیشه فارسی است.
مرتبط: کدهای خطا، API ورود داده، API مدیریتی.