پردازش غیرهمزمان و اعلان
نسخه اول از صف پایدار PostgreSQL و Worker همان Codebase استفاده میکند. Redis، RabbitMQ و Kafka تا زمانی که Metric نیاز عملیاتی آنها را اثبات نکرده است اضافه نمیشوند.
کاربرد Job
کار باید غیرهمزمان شود اگر یکی از شرایط زیر برقرار است:
- به SMS، Push، Webhook، Object Storage یا Provider بیرونی وابسته است.
- ممکن است از بودجه پاسخ API عبور کند.
- Retry، Schedule، Batch یا Rate Limit Provider لازم دارد.
- نتیجه آن پس از Commit کسبوکار قابل انجام است.
Validation، Authorization و Invariant اصلی داخل Request و پیش از ثبت Job انجام میشوند. Job نباید خطای قابل پیشبینی کاربر را دیرهنگام کشف کند.
Transactional Outbox
تغییر داده دامنه و ثبت Event Outbox در یک Transaction انجام میشود. Worker پس از Commit، Event را به Job یا Delivery تبدیل میکند. Dual-write مستقیم «Database سپس Provider» یا برعکس ممنوع است.
هر Event شامل شناسه یکتا، نوع نسخهدار، Aggregate، Tenant، زمان وقوع، Correlation ID و Payload حداقلی است. PII و Snapshot بزرگ بدون نیاز وارد Event نمیشود.
مدل Job
| فیلد | هدف |
|---|---|
id |
UUIDv7 یکتا |
type و version |
Handler و قرارداد Payload |
tenant_id |
Scope و Fairness |
idempotency_key |
جلوگیری از اجرای اثر تکراری |
payload |
داده حداقلی JSONB یا Reference پایدار |
status |
pending، running، succeeded، retryable، dead |
attempts و max_attempts |
سیاست Retry |
available_at |
Schedule و Backoff |
locked_by و locked_until |
Lease و بازیابی Worker مرده |
last_error_code |
خطای Redacted و قابل گروهبندی |
Worker با FOR UPDATE SKIP LOCKED یک Batch محدود Claim میکند و Lock را سریع آزاد میکند. Lease منقضیشده قابل بازیابی است و Heartbeat فقط برای کار طولانی مجاز است.
Idempotency و Delivery
- Semantics صف حداقل یکبار است؛ Handler باید Idempotent باشد.
- اثر نهایی با Unique Constraint، Inbox Table Provider یا State Check دامنهای محافظت میشود.
- موفقیت فقط پس از تایید نتیجه پایدار ثبت میشود.
- Timeout مبهم Provider پیش از Retry با Query وضعیت یا Idempotency Provider Reconcile میشود.
- ترتیب فقط در Aggregateهایی که نیاز واقعی دارند حفظ میشود؛ Sequence سراسری هزینه غیرضروری دارد.
- Event قدیمی با Upcaster یا Handler نسخه خودش خوانده میشود و Payload Mergeشده ویرایش نمیشود.
Retry و Dead Letter
- خطا به Permanent، Retryable و Unknown طبقهبندی میشود.
- Retry با Exponential Backoff، Full Jitter، سقف زمانی و حداکثر تلاش محدود اجرا میشود.
429وRetry-AfterProvider رعایت میشوند؛4xxقطعی بدون Retry به Dead Letter یا نتیجه کسبوکار میرود.- پس از پایان تلاشها Job به
deadمیرود، Alert و ابزار Replay کنترلشده ایجاد میشود. - Replay نیازمند Permission عملیاتی، دلیل، Audit و Idempotency است؛ ویرایش Payload تاریخی ممنوع است.
- Poison Job نباید Queue یک Tenant یا Type دیگر را متوقف کند.
Fairness و فشار معکوس
- Concurrency برای هر Job Type و Provider محدود است.
- Tenant پرمصرف نباید تمام Workerها را اشغال کند؛ Claim و Rate Limit باید Fairness حداقلی داشته باشد.
- Queue Depth، Age قدیمیترین Job، Throughput، Retry Rate، Dead Count و زمان Handler Metric دارند.
- در Backlog بالا، Job کماولویت دیرتر اجرا و مسیرهای حیاتی مانند OTP و مالی ظرفیت رزروشده دارند.
- API در Overload بهجای پذیرش بینهایت، Backpressure و
503یا429کنترلشده میدهد.
مدل اعلان
Inbox داخل برنامه منبع حقیقت اعلان است. هر رویداد بر اساس Policy به یک یا چند کانال تبدیل میشود:
| کانال | کاربرد |
|---|---|
| In-app Inbox | همه اعلانهای قابل پیگیری و تاریخچهدار |
| SSE | بهروزرسانی Foreground وب |
| Push | آگاهسازی Background موبایل |
| SMS | OTP و رویدادهای بحرانی، رسمی یا مالی تصویبشده |
- Preference کاربر، Permission، عضویت فعال، Quiet Hours و حساسیت محتوا پیش از Delivery بررسی میشوند.
- Push Payload شامل Secret یا متن حساس کامل نیست و Client پس از بازشدن Detail را از REST میگیرد.
- Token دستگاه Lifecycle دارد؛ Token نامعتبر Provider غیرفعال و Cleanup میشود.
- Deduplication بر اساس Recipient، Event و Channel انجام میشود.
- Delivery و Read State جدا هستند؛ تحویل Push به معنی خواندن پیام نیست.
- Template نسخهدار، قابل Preview و دارای Fallback فارسی است.
Ticket
Ticket یک Workflow دامنهای است، نه Chat. Feature آن باید ایجاد، دستهبندی، Assignment، SLA، پاسخ، یادداشت داخلی، Attachment، تغییر Status، تصمیم، Resolution و Audit را نگهداری کند. پیام داخلی فقط برای نقش مجاز قابل مشاهده است و هر Transition با استاندارد Workflow سازگار میماند.
معیار پذیرش
- Crash Worker بین اثر بیرونی و ثبت Success باعث اثر تکراری غیرمجاز نمیشود.
- Job منقضی یا Poison بهصورت قابل مشاهده Dead Letter میشود.
- Queue OTP زیر بار Jobهای کماولویت همچنان ظرفیت هدف دارد.
- از دست رفتن Push یا SSE با Sync از Inbox جبران میشود.
- Replay عملیاتی Permission، Audit و نتیجه قابل ردیابی دارد.