تطوير Laravel

تطبيقات Laravel، نبنيها ونُبقيها تعمل.

من أول نموذج إلى عمّال الطوابير، ومن النشر إلى الترقية بعد سنوات — يكتبها ويستضيفها ويرعاها فريق واحد.

إصدار، كما يبدو على الخادم

كل تطبيق Laravel نشغّله يخرج بالطريقة نفسها: يُختبر ويُبنى ويُخزَّن مؤقتًا ويُفعَّل دون ثانية واحدة من التوقف.

ci ~/app $ php artisan test   PASS  Tests\Feature\CheckoutTest  ✓ a paid order queues the invoice  ✓ a declined card never marks the order paid   PASS  Tests\Unit\VatTest  ✓ vat is added once, on the total app ~/releases/1400 $ composer install --no-dev --optimize-autoloaderInstalling dependencies from lock fileGenerating optimized autoload files app ~/releases/1400 $ php artisan migrate --force   INFO  Running migrations.  2026_09_27_090000_add_due_date_to_invoices ....... DONE app ~/releases/1400 $ php artisan optimize   INFO  Caching framework bootstrap, configuration, and metadata.  config ...................................... DONE  events ...................................... DONE  routes ...................................... DONE  views ....................................... DONE app ~/releases/1400 $ ln -sfn ~/releases/1400 ~/currentapp ~/releases/1400 $ php artisan horizon:terminate && php artisan octane:reload app ~/releases/1400 $ sudo supervisorctl statushorizon                 RUNNING   pid 48211, uptime 0:00:09octane                  RUNNING   pid 31877, uptime 6 days, 2:14:51 app ~/releases/1400 $ php artisan schedule:list  */5 * * * *  php artisan horizon:snapshot ... Next Due: 3 minutes from now  0   2 * * *  php artisan model:prune ........ Next Due: 9 hours from now  0   9 * * *  php artisan invoices:remind .... Next Due: 16 hours from now
جلسة توضيحية على تطبيق توضيحي. الأسماء والمسارات والمخرجات للتوضيح فقط.
  1. الاختبارات أولًا

    تعمل الاختبارات قبل أن يصل أي شيء إلى الخادم. واختبار واحد فاشل يوقف الإصدار.

  2. الاعتماديات

    تُثبَّت من ملف القفل فقط، دون حزم التطوير، ومع محمِّل تلقائي مُحسَّن للأصناف.

  3. الترحيلات

    تُكتب بحيث تظل الشيفرة العاملة صالحة مع المخطط الجديد خلال انتقال الإصدار.

  4. التخزين المؤقت

    تُخزَّن الإعدادات والأحداث والمسارات وقوالب العرض مؤقتًا. ومن هنا فصاعدًا لا يُقرأ ملف البيئة إطلاقًا، ولهذا يقتصر مكان env()‎ على ملفات الإعدادات.

  5. التبديل

    يُحوَّل رابط واحد فيدخل الإصدار الجديد الخدمة. ويبقى الإصدار السابق على القرص للرجوع إليه.

  6. العمّال

    يُنهي Horizon المهام التي بين يديه ثم يُعاد تشغيله على الشيفرة الجديدة، ويعيد Octane تحميل عمّاله بالطريقة نفسها.

  7. تحت الإشراف

    يُبقي Supervisor كلًّا من Horizon وOctane قيد التشغيل، ويعيد أيًّا منهما إذا توقف.

  8. المُجدوِل

    سطر cron واحد يشغّل كل مهمة مجدولة. وهذا ما سيشغّله تاليًا.

من نقرة واحدة إلى مهمة مكتملة

يخرج العمل البطيء من الطلب. يحصل العميل على ردّ فوري، ويتولى عامل الباقي في الخلفية.

  1. 01 · الطلب POST /checkout

    العميل يدفع

    يتحقق المتحكّم من الطلب ويحفظه ويردّ فورًا. لا يجري هنا أي شيء بطيء.

  2. 02 · المهمة PayOrder::dispatch()

    الجزء البطيء يصبح مهمة

    تُرسَل بعد أن تُثبِّت قاعدة البيانات المعاملة، فلا يلتقط أي عامل طلبًا جرى التراجع عنه.

  3. 03 · الطابور redis · payments

    تنتظر في طابورها الخاص

    للمدفوعات طابورها الخاص، فلا يؤخرها تصدير طويل أبدًا.

  4. 04 · العامل horizon · supervisor

    يتسلّمها عامل

    مع مهلة زمنية، وإعادة محاولات يطول انتظارها في كل مرة، وحدّ لعدد ما يعمل منها في وقت واحد.

  5. 05 · الإشعار OrderPaid → mail, database

    يُبلَّغ الجميع

    يتلقى العميل الفاتورة بالبريد الإلكتروني، ويتحول الطلب إلى «مدفوع» في لوحة التحكم لديك.

إذا استمر الفشل failed_jobs

المهمة التي تستنفد محاولاتها تُحفظ مع خطئها، ويصلنا تنبيه. ويُعاد تشغيلها بعد إصلاح السبب — ولا تضيع في صمت أبدًا.

التطبيق كله، لا الخادم وحده

يحمل فريقنا خبرة خمسة وعشرين عامًا في PHP إلى كل مشروع Laravel، من أول نموذج إلى الترقية بعد سنوات.

نبني

التطبيق نفسه.

البنية
منطق الأعمال في أصناف الإجراءات والخدمات، لا في المتحكّمات. طلبات نماذج مخصّصة للتحقق من المدخلات، وسياسات تحدد من يحق له فعل ماذا.
Eloquent
تُحمَّل العلاقات مسبقًا حيث تعرضها الصفحة في قائمة، فتكلّف الصفحة بضعة استعلامات لا المئات. وفي بيئة التطوير يُطلق التحميل الكسول خطأً، فتُكتشف المشكلة مبكرًا.
Livewire · Inertia
Livewire حين يكتب الفريق بـ PHP وBlade؛ وInertia مع Vue أو React حين تكون الواجهة الأمامية مشروعًا قائمًا بذاته.
واجهات API مع Sanctum
رموز وصول لتطبيقات الجوال والشركاء، وجلسات عبر ملفات تعريف الارتباط لواجهتك الأمامية، وحدود لمعدّل الطلبات لكل عميل.
Pest · PHPUnit
اختبارات لكل مسار يتقاضى مالًا أو يرسل بريدًا، تعمل مع كل رفع للشيفرة قبل بناء أي إصدار.

نشغّل

ما يُبقيه مستجيبًا.

الطوابير وHorizon
طوابير منفصلة للأعمال العاجلة والأعمال المجمّعة، لكلٍّ منها عمّاله ومُهَله وإعادات محاولته، تحت المراقبة في لوحة Horizon.
المُجدوِل
سطر cron واحد يشغّل كل المهام. والمهام التي يجب ألا تتداخل، أو يجب أن تعمل على خادم واحد فقط، تُعلَّم بذلك.
Octane
يُبقي Swoole أو RoadRunner أو FrankenPHP التطبيق في الذاكرة بين الطلبات. وقبل أن نفعّله، نفحص الشيفرة بحثًا عن أي حالة تتسرّب من طلب إلى الطلب الذي يليه.
Redis
التخزين المؤقت والجلسات والطوابير والأقفال، على Redis لا يمكن الوصول إليه من الإنترنت.
Supervisor
يعمل عمّال الطوابير وHorizon وOctane كعمليات تحت الإشراف، يُعاد تشغيلها إذا توقفت وبعد كل إصدار.

نصون

ما يُبقيه محدَّثًا.

نشر دون توقف
يُبنى كل إصدار في مجلده الخاص ويُفعَّل بتحويل رابط واحد. والعودة هي الخطوة نفسها بالعكس.
السجلات والاستثناءات
ملفات سجلات يومية تُحفظ لمدة محددة، وكل استثناء يُبلَّغ إلينا مع الطلب الذي تسبب فيه.
الترقيات
يُصدر Laravel إصدارًا رئيسيًا كل عام. وننقل التطبيق إصدارًا واحدًا في كل مرة، مع نجاح الاختبارات في كل خطوة.

ما نُعِدّه من اليوم الأول

قبل أن يصل أول عميل، يكون كل هذا جاهزًا على كل خادم Laravel نشغّله.

  • وضع التصحيح مُعطَّل في بيئة الإنتاج، ولا يُتاح للويب إلا المجلد العامAPP_DEBUG=false
  • عمّال الطوابير تحت Supervisor، ويُعاد تشغيلهم مع كل إصدارsupervisord
  • سطر cron واحد للمُجدوِل* * * * * php artisan schedule:run
  • Redis للتخزين المؤقت والجلسات والطوابيرCACHE_STORE=redis
  • الإعدادات والأحداث والمسارات وقوالب العرض مخزّنة مؤقتًا مع كل إصدارphp artisan optimize
  • OPcache مُفعَّل، ويُعاد ضبطه مع كل إصدارopcache.validate_timestamps=0
  • مجموعة PHP-FPM بحجم يناسب ذاكرة الخادمpm.max_children
  • الإصدارات في مجلداتها الخاصة، على بُعد خطوة واحدة من الرجوعcurrent → releases/…
  • المهام الفاشلة تُبلَّغ إلينا، ولا تُترك في جدولfailed_jobs
  • تدوير السجلات وتنبيهات الاستثناءاتLOG_CHANNEL=daily
  • نسخة احتياطية ليلية لقاعدة البيانات، تُنسخ خارج الخادمbackup · offsite
  • شهادة TLS تتجدد تلقائيًاLet's Encrypt

إصدار على القرص

/var/www/example-app
├── current → releases/1400
├── releases/
│   ├── 1400
│   └── 0930
└── shared/
    ├── .env
    └── storage/
يشير خادم الويب إلى current. ويدخل الإصدار الخدمة لحظة تحويل الرابط، ويبقى الإصدار السابق للرجوع إليه.

أخبرنا عن تطبيقك

تطبيق جديد، أو تطبيق يحتاج إلى استضافة، أو تطبيق عالق على إصدار قديم. يُسعَّر كل مشروع بعد محادثة قصيرة.