عملیات
استقرار
Pitchbar با هدف اصلی استقرار روی Laravel Cloud ساخته شده است — پشته شامل FrankenPHP + Postgres + Redis است که Laravel Cloud بهصورت بومی همه را ارائه میدهد. خودمیزبانی نیز پشتیبانی میشود اما اپراتور مسئولیت بیشتری دارد.
Laravel Cloud
فایل infra/cloud.yaml در مخزن، محیطها و فرآیندها را شرح میدهد. ساختار کلی:
- منطقه: بهطور پیشفرض
us-east. براساس نزدیکی به مشتریان خود انتخاب کنید. - فرآیند برنامه: FrankenPHP، حالت Octane. مقیاسپذیری خودکار.
- فرآیند پردازشگر: Horizon، اختصاصی برای صفهای
crawl،indexوdefault. - فرآیند Reverb: سرور WebSocket پایدار.
- Postgres: نسخه ۱۶، با پشتیبانگیری روزانه.
- Redis: نسخه ۷، پایدار.
محیطها
| محیط | کاربرد |
|---|---|
| preview | محیطهای موقت برای هر درخواست کشش. با باز شدن درخواست کشش بهطور خودکار ایجاد و با ادغام/بسته شدن حذف میشود. |
| staging | طولانیمدت. پیکربندی را به تولید آینه میکند. برای تضمین کیفیت و تأیید پیش از انتشار استفاده میشود. |
| production | محیط رو به مشتری. انتشار با شرط موفقیت CI + استقرار دستی انجام میشود. |
اندازهگیری محاسبات برای نسخه v1
نقطه شروع. براساس ترافیک تنظیم کنید.
| کامپوننت | اندازه | دلیل |
|---|---|---|
| برنامه (Octane) | ۲ نمونه × ۲ vCPU / ۲ گیگابایت | مسیر اصلی بیشتر به خروجی جریانی هوش مصنوعی محدود است. دو نمونه برای در دسترس بودن بالا. |
| پردازشگر (Horizon) | ۲ نمونه × ۲ vCPU / ۲ گیگابایت | توان پردازش خودکار. براساس عمق صف مقیاس کنید. |
| Reverb | ۱ نمونه × ۱ vCPU / ۱ گیگابایت | WebSocket، چسبنده. |
| Postgres | ۲ vCPU / ۴ گیگابایت / ۵۰ گیگابایت SSD | تا حدود ۱۰ میلیون پیام راحت است. |
| Redis | ۱ گیگابایت | نشستها، صف، کشهای سریع. |
دامنهها
معمولاً نیاز دارید:
- دامنه اصلی —
app.pitchbar.comبرای برنامه مشتری / مدیریت. - دامنه ویجت — همان یا یک
cdn.pitchbar.comجداگانه که/widget/widget.jsرا ارائه میدهد. بسته دارای یک پارامتر پرسش هش محتوا است، بنابراین کشگذاری تهاجمی ایمن است. - دامنه Reverb —
realtime.pitchbar.comاگر فرآیند WebSocket را روی میزبان خود جدا کنید.
CI/CD
گردشهای GitHub Actions در .github/workflows/:
tests.yml— راهاندازی PHP + Composer + مجموعه Pest (با دادههای ساختگی، بدون شبکه).lint.yml— Pint، ESLint، TypeScripttsc --noEmit.widget.yml— ساخت بسته ویجت + بررسی بودجه حجم.
استقرارها با شرط موفقیت CI انجام میشوند؛ مرحله استقرار واقعی در Laravel Cloud (یا معادل هاستینگ شما) پیکربندی میشود، نه در فایلهای فرآیند خودکار.
مهاجرتها
Laravel Cloud php artisan migrate --force را در هر استقرار اجرا میکند. مهاجرتها باید با نسخههای قبلی سازگار باشند — استقراری که یک ستون NOT NULL را به یک جدول پر شده اضافه میکند، نیاز به دو مرحله دارد:
- استقرار ۱: ستون را بهصورت nullable اضافه کنید، دادههای قبلی را پر کنید، کد برنامه شروع به نوشتن در آن میکند.
- استقرار ۲: ستون را به NOT NULL تغییر دهید.
همین قوانین برای تغییر نام و حذف نیز صدق میکند — هرگز در یک استقرار واحد، مخرب نباشید.
پشتیبانگیری
- Postgres — تصاویر روزانه، به مدت ۳۰ روز نگهداری میشوند. بازیابی نقطهبهزمان فعال است.
- ذخیرهساز جستجوی هوشمند — Cloudflare Vectorize / Qdrant پشتیبانگیری داخلی ندارند؛ با ارسال مجدد
IndexDocumentJobبرای هر سند از جدولchunksبازسازی کنید.php artisan pitchbar:audit-vectorsمغایرت بین جدول chunks و ذخیرهساز جستجوی هوشمند زنده را گزارش میدهد؛ اگر نیاز به تعمیر دارید، وظیفه را به ازای هر ردیف ارسال کنید. - R2 / ذخیرهسازی اشیاء — نسخهگذاری فعال است.
- اسرار برنامه — فروشگاه اسرار Laravel Cloud رمزگذاری شده است؛ از
APP_KEYبهطور جداگانه پشتیبانگیری کنید (کلید اصلی برای رمزگذاری app_settings است).
بازگشت به نسخه قبلی
Laravel Cloud نسخه قبلی را برای بازگشت فوری نگهداری میکند. برای بازگشتهای ناسازگار با ساختار (نادر)، از آخرین تصویر بازیابی کنید.
خودمیزبانی
همان تنظیمات Docker که docker-compose.yml را اجرا میکند، با چند افزودنی برای تولید کار میکند:
- پراکسی معکوس (Caddy یا Nginx) که TLS را در جلوی FrankenPHP خاتمه میدهد.
- Postgres + Redis مدیریتشده (یا خودمدیریتی با کپیهای با در دسترس بودن بالا).
- Horizon بهعنوان یک سرویس طولانیمدت که توسط systemd / یک مدیر فرآیند نظارت میشود.
- Reverb بهعنوان فرآیند خود.
- کلکسیونر Sentry / OTEL که بهصورت محلی اجرا میشود یا به یک سرویس ابری اشاره میکند.
میانبر composer run dev همه چیز را بهصورت محلی (Octane، پردازشگر صف، Reverb، vite) برای توسعه راهاندازی میکند.
تیک پردازشگر صف از طریق cron پردازشگر Cloudflare
زمانی که زمانبندی درونخوشهای در دسترس نباشد (هاست اشتراکی cPanel، VPS دستی بدون systemd، محیطهای پیشنمایش Laravel Cloud)، یک پردازشگر خارجی Cloudflare میتواند هر ۶۰ ثانیه با ارسال درخواست POST به /api/v1/internal/queue-tick با کلید مخفی INTERNAL_QUEUE_TOKEN، صف را هدایت کند. این نقطه پایانی، php artisan queue:tick را فراخوانی میکند که یک بار queue:work --once --stop-when-empty را با تنظیمات پیشفرض زیر اجرا میکند:
--max-time=55— حلقه قبل از مرز ۶۰ ثانیهای تیک خارج میشود تا تیکهای متوالی روی هم انباشته نشوند.--job-timeout=120— وظایف جداگانه (بیشتر CrawlPageJob / IndexDocumentJob) سقف ۲ دقیقهای دارند.- صفهای پردازششده:
crawl,index,default.
پردازشگر را از طریق php artisan pitchbar:deploy-cron-worker ساخته و استقرار دهید. بدنه پردازشگر از WorkerDeployer قالببندی شده و با پارامترهای تیک درونساخته ارسال میشود. پس از استقرار، INTERNAL_QUEUE_TOKEN را تغییر دهید.
قابلیت اطمینان خزنده
CrawlPageJob تا ۳ بار با فاصلههای [30, 90, 180] ثانیه تلاش مجدد میکند. مسیر تلاش مجدد براساس کلاس خطا منشعب میشود:
- محدودیت نرخ (429) —
release(60)بدون مصرف یک جایگاه تلاش مجدد. هر صفحه گسترشیافته معمولاً به همان موج 429 برخورد میکند؛ انتظار مشترک مفید است. - خطاهای دائمی — خطاهای DNS curl (6، 7)، رد اتصال، آدرس بدفرم، HTTP 400 / 401 / 403 / 404 / 410 / 451 — بلافاصله
$this->fail()را فراخوانی کنید. بدون این، هر آدرس مرده بودجه کامل ۳ تلاش مجدد را میسوزاند و یکMaxAttemptsExceededExceptionعمومی در لاگها تولید میکرد. - موقتی (5xx، نوسان شبکه) — تلاش مجدد معمولی با فاصله.
زمانبندی هر وظیفه ۹۰ ثانیه است؛ failOnTimeout=true به این معنی است که SIGTERM در زمانبندی همچنان failed() را اجرا کرده و ردیف منبع را با یک خطای قابل خواندن برای مشتری به failed تغییر میدهد.