Pengembangan Laravel

Aplikasi Laravel, dibangun dan dijaga tetap berjalan.

Dari model pertama hingga worker antrean, deploy, dan upgrade bertahun-tahun kemudian – ditulis, di-host, dan dirawat oleh satu tim.

Sebuah rilis, seperti yang terlihat di server

Setiap aplikasi Laravel yang kami jalankan dirilis dengan cara yang sama: diuji, dibangun, di-cache, dan diaktifkan tanpa downtime sedetik pun.

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
Contoh sesi pada contoh aplikasi. Nama, path, dan keluaran bersifat ilustratif.
  1. Tes dulu

    Tes dijalankan sebelum apa pun sampai ke server. Satu tes yang gagal menghentikan rilis.

  2. Dependensi

    Dipasang hanya dari file lock, tanpa paket pengembangan, dengan autoloader yang dioptimalkan.

  3. Migrasi

    Ditulis agar kode yang sedang berjalan tetap berfungsi dengan skema baru selama rilis beralih.

  4. Cache

    Konfigurasi, event, route, dan view di-cache. Sejak titik ini file environment tidak dibaca sama sekali, karena itulah env() hanya layak berada di file konfigurasi.

  5. Peralihan

    Satu tautan dipindahkan dan rilis baru langsung aktif. Rilis sebelumnya tetap di disk untuk rollback.

  6. Worker

    Horizon menuntaskan job yang sedang dikerjakan lalu memulai ulang dengan kode baru; Octane memuat ulang worker-nya dengan cara yang sama.

  7. Diawasi

    Supervisor menjaga Horizon dan Octane tetap berjalan, dan menghidupkan kembali salah satunya jika berhenti.

  8. Penjadwal

    Satu baris cron menjalankan setiap tugas terjadwal. Inilah yang akan dijalankannya berikutnya.

Dari satu klik hingga job yang selesai

Pekerjaan yang lambat keluar dari permintaan. Pelanggan langsung mendapat jawaban, dan worker mengerjakan sisanya di latar belakang.

  1. 01 · Permintaan POST /checkout

    Pelanggan membayar

    Controller memvalidasi pesanan, menyimpannya, dan langsung menjawab. Tidak ada proses lambat di sini.

  2. 02 · Job PayOrder::dispatch()

    Bagian yang lambat menjadi job

    Dikirim setelah database melakukan commit, sehingga worker tidak pernah mengambil pesanan yang sudah di-rollback.

  3. 03 · Antrean redis · payments

    Menunggu di antreannya sendiri

    Pembayaran punya antrean sendiri, sehingga ekspor yang panjang tidak pernah menahannya.

  4. 04 · Worker horizon · supervisor

    Sebuah worker mengambilnya

    Dengan batas waktu, percobaan ulang yang menunggu makin lama setiap kali, dan batas jumlah yang berjalan bersamaan.

  5. 05 · Notifikasi OrderPaid → mail, database

    Semua diberi tahu

    Pelanggan menerima faktur lewat email, dan status pesanan berubah menjadi lunas di dasbor Anda.

Jika terus gagal failed_jobs

Job yang kehabisan percobaan ulang disimpan beserta error-nya, dan kami menerima peringatan. Job itu dicoba ulang setelah penyebabnya diperbaiki – tidak pernah hilang diam-diam.

Seluruh aplikasi, bukan hanya servernya

Tim kami membawa pengalaman PHP selama dua puluh lima tahun ke setiap proyek Laravel, dari model pertama hingga upgrade bertahun-tahun kemudian.

Bangun

Aplikasinya sendiri.

Arsitektur
Logika bisnis di action dan service, bukan di controller. Form request untuk validasi, policy untuk siapa boleh melakukan apa.
Eloquent
Relasi dimuat di awal saat sebuah halaman menampilkannya dalam daftar, sehingga satu halaman hanya butuh beberapa query, bukan ratusan. Saat pengembangan, lazy loading memicu error, sehingga masalahnya tertangkap sejak awal.
Livewire · Inertia
Livewire saat tim menulis PHP dan Blade; Inertia dengan Vue atau React saat front end adalah proyek tersendiri.
API dengan Sanctum
Token untuk aplikasi seluler dan mitra, sesi cookie untuk front end Anda sendiri, dan batas laju per klien.
Pest · PHPUnit
Tes untuk setiap alur yang menerima uang atau mengirim email, dijalankan pada setiap push sebelum rilis dibangun.

Jalankan

Yang membuatnya tetap merespons.

Antrean dan Horizon
Antrean terpisah untuk pekerjaan mendesak dan massal, masing-masing dengan worker, batas waktu, dan percobaan ulangnya sendiri, dipantau di dasbor Horizon.
Penjadwal
Satu baris cron menjalankan setiap tugas. Tugas yang tidak boleh tumpang-tindih, atau harus berjalan di satu server saja, ditandai demikian.
Octane
Swoole, RoadRunner, atau FrankenPHP menyimpan aplikasi di memori di antara permintaan. Sebelum mengaktifkannya, kami memeriksa kode untuk state yang bocor dari satu permintaan ke permintaan berikutnya.
Redis
Cache, sesi, antrean, dan lock, di Redis yang tidak bisa dijangkau dari internet.
Supervisor
Worker antrean, Horizon, dan Octane berjalan sebagai proses yang diawasi, dimulai ulang jika berhenti dan setelah setiap rilis.

Rawat

Yang membuatnya tetap mutakhir.

Deploy tanpa downtime
Setiap rilis dibangun di direktorinya sendiri dan diaktifkan dengan satu tautan. Kembali ke versi sebelumnya adalah langkah yang sama secara terbalik.
Log dan eksepsi
File log harian yang disimpan selama jangka waktu tertentu, dan setiap eksepsi dilaporkan kepada kami beserta permintaan yang memicunya.
Upgrade
Laravel merilis versi mayor setiap tahun. Kami memindahkan aplikasi satu versi demi satu versi, dengan tes yang lolos di setiap langkah.

Yang kami siapkan sejak hari pertama

Sebelum pelanggan pertama datang, setiap server Laravel yang kami jalankan sudah memiliki semua ini.

  • Mode debug mati di produksi, dan hanya direktori public yang disajikan ke webAPP_DEBUG=false
  • Worker antrean di bawah Supervisor, dimulai ulang di setiap rilissupervisord
  • Satu baris cron untuk penjadwal* * * * * php artisan schedule:run
  • Redis untuk cache, sesi, dan antreanCACHE_STORE=redis
  • Konfigurasi, event, route, dan view di-cache di setiap rilisphp artisan optimize
  • OPcache aktif, dan di-reset di setiap rilisopcache.validate_timestamps=0
  • Pool PHP-FPM yang disesuaikan dengan memori serverpm.max_children
  • Rilis di direktorinya sendiri, satu langkah dari rollbackcurrent → releases/…
  • Job yang gagal dilaporkan kepada kami, tidak dibiarkan di tabelfailed_jobs
  • Rotasi log dan peringatan eksepsiLOG_CHANNEL=daily
  • Cadangan database setiap malam, disalin ke luar serverbackup · offsite
  • Sertifikat TLS yang diperbarui sendiriLet's Encrypt

Rilis di disk

/var/www/example-app
├── current → releases/1400
├── releases/
│   ├── 1400
│   └── 0930
└── shared/
    ├── .env
    └── storage/
Server web mengarah ke current. Rilis aktif begitu tautannya dipindahkan, dan rilis sebelumnya tetap disimpan untuk rollback.

Ceritakan tentang aplikasi Anda

Proyek baru, aplikasi yang butuh tempat, atau aplikasi yang tertahan di versi lama. Setiap proyek diberi penawaran setelah percakapan singkat.