Panel Cache di Production
php artisan panel:cache menjalankan discovery satu kali saat deploy lalu menulis class name yang dimiliki setiap Panel ke bootstrap/cache/panels.php. Setelah file tersebut tersedia, discovery tidak berjalan lagi: tidak ada filesystem scan, reflection, atau pekerjaan discovery per request. Gunakan halaman ini ketika memasukkan panel:cache ke deploy pipeline, ketika menggunakan release directory/symlink, atau ketika Resource hilang dari Panel production tanpa log apa pun.
Contoh minimal yang berfungsi
composer install --no-dev --optimize-autoloader
php artisan panel:cache2
INFO Panels cached: 2 panels, 1 resources, 5 pages, 4 widgets.Karena command diregistrasikan sebagai hook optimize, Anda juga dapat menjalankan:
php artisan optimize # config, routes, events, views — dan panel:cache
php artisan optimize:clear # termasuk panel:clear2
Hook menggunakan key panels, sehingga dapat dikecualikan:
php artisan optimize --except=panels
php artisan optimize:clear --except=panels2
Posisi dalam deploy pipeline
composer install --no-dev --prefer-dist --optimize-autoloader # 1
php artisan migrate --force # 2
npm ci && npm run build # 3
php artisan optimize # 4 ← di sini
php artisan queue:restart # 52
3
4
5
panel:cache harus dijalankan setelah Composer karena discovery menerjemahkan filesystem path menjadi class name melalui Composer PSR-4 prefix map. Manifest yang dibuat terhadap autoloader release sebelumnya dapat menunjuk ke class yang sudah berpindah.
Jalankan cache sebelum worker direstart, karena worker menggunakan manifest yang sama dengan web process.
File yang dihasilkan
use PandaPanel\Cache\PanelManifest;
PanelManifest::path(); // '/var/www/releases/42/bootstrap/cache/panels.php'2
3
Contoh isi:
<?php
// Generated by "php artisan panel:cache". Do not edit.
return array (
'panels' =>
array (
'admin' =>
array (
'resources' =>
array (
0 => 'App\\Panels\\Admin\\Resources\\Users\\UserResource',
),
'pages' => array ( /* ... */ ),
'widgets' => array ( /* ... */ ),
),
),
'fingerprint' => '…',
);2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Yang disimpan hanya class name. File dibuat dengan var_export(), bukan serialized blob, sehingga:
- merupakan PHP source biasa dengan
return [...]; - dapat di-cache opcache;
- mudah dibaca manusia;
- deterministic.
Daftar per Panel adalah gabungan explicit registration + discovery, sudah dideduplicate dan diurutkan. Dua machine dengan code yang sama menghasilkan file yang byte-identical.
Path menggunakan application bootstrapPath(), bukan base_path('bootstrap/...'). Ini penting untuk application yang memindahkan bootstrap directory dan memastikan optimize:clear membersihkan file yang benar.
Penulisan bersifat atomic
$temporary = self::path().'.'.getmypid().'.tmp';
File::put($temporary, $this->render([...]))
File::move($temporary, self::path());2
3
4
Manifest dirender ke panels.php.{pid}.tmp, lalu dipindahkan menjadi file final. Request yang datang saat cache sedang dibangun akan membaca manifest lama atau manifest baru, tidak pernah file setengah tertulis. Dua process yang melakukan cache bersamaan juga tidak menulis isi yang saling bercampur.
Secara teknis ini membuat panel:cache aman terhadap traffic yang sedang hidup, tetapi deployment dengan release directory tetap lebih baik membangunnya pada release baru sebelum symlink dipindah.
API di balik command
PandaPanel\Cache\PanelManifest adalah singleton dan merupakan satu-satunya reader/writer manifest.
| Method | Signature | Catatan |
|---|---|---|
path | static path(): string | app()->bootstrapPath('cache/panels.php') |
exists | exists(): bool | apakah file tersedia |
for | for(Panel $panel): array{resources: list<string>, pages: list<string>, widgets: list<string>} | membaca manifest jika ada, discovery jika tidak |
write | write(PanelRegistry $registry): array | membangun seluruh registered Panel lalu menulis atomic |
clear | clear(): bool | menghapus file dan melupakan in-memory copy |
warnIfStale | warnIfStale(PanelRegistry $registry): void | development only |
use PandaPanel\Cache\PanelManifest;
use PandaPanel\Core\PanelManager;
use PandaPanel\Core\PanelRegistry;
$manifest = app(PanelManifest::class);
$manifest->exists();
$manifest->for(app(PanelManager::class)->get('admin'));
$manifest->write(app(PanelRegistry::class));
$manifest->clear();2
3
4
5
6
7
8
9
10
Health check sederhana:
use PandaPanel\Cache\PanelManifest;
abort_unless(app(PanelManifest::class)->exists(), 503, 'Panels are not cached.');2
3
for() adalah seam yang dilalui setiap Panel ketika registration. Jika Panel tersedia di manifest, class list berasal dari file tersebut. Jika Panel tidak ada — misalnya Panel test atau Panel yang diregistrasikan setelah manifest dibuat — hanya Panel tersebut yang fallback ke discovery.
Karena fallback tersebut, stale manifest sering gagal secara senyap, bukan menjadi fatal error.
Release directory dan symlink
Deployment model dengan release directory + symlink bekerja dengan satu aturan penting:
bootstrap/cacheharus menjadi milik masing-masing release, jangan dishare antar-release.
| Directory | Shared antar-release? |
|---|---|
storage | ya |
.env | ya |
bootstrap/cache | tidak |
Manifest mendeskripsikan class yang ada pada satu release. Jika bootstrap/cache dishare, rollback ke release lama dapat tetap memakai manifest release baru yang menyebut class yang sudah tidak ada.
Karena manifest dianggap authoritative, discovery tidak otomatis datang menyelamatkan kondisi tersebut.
Build cache di release baru sebelum symlink dipindah:
cd /var/www/releases/42
php artisan optimize
ln -sfn /var/www/releases/42 /var/www/current2
3
Opcache
Manifest merupakan PHP source. Pada server dengan:
opcache.validate_timestamps=0compiled copy release lama dapat tetap berada di opcache sampai reset dilakukan. Ini bukan masalah khusus PandaBear; hal yang sama berlaku untuk cached config/routes.
Jika deploy application sudah melakukan opcache reset, panels.php ikut ter-cover.
Octane dan long-lived process
PanelManifest adalah singleton dan parsed manifest di-cache di memory. Worker yang sudah membaca manifest akan terus menggunakan copy tersebut sampai worker direcycle.
php artisan octane:reload
php artisan queue:restart2
Menjalankan panel:clear dari CLI hanya membersihkan process CLI dan file disk. Ia tidak dapat menghapus memory copy pada worker yang sedang hidup. Karena itu deploy tetap harus me-restart/reload long-lived worker.
Lihat Octane.
Warning stale tidak aktif di production
if (! app()->hasDebugModeEnabled() && ! app()->environment('local', 'testing')) {
return;
}2
3
warnIfStale() membandingkan fingerprint berupa:
- jumlah PHP file di discovery path;
- newest modification time.
Pada local, testing, atau debug mode, mismatch menghasilkan warning bahwa manifest stale dan class baru tidak terlihat sampai cache dibersihkan.
Production sengaja tidak menjalankan check ini karena manifest dianggap source of truth dan filesystem check akan menambah stat() operation terhadap banyak file.
Konsekuensinya harus dipahami jelas:
Deploy production yang lupa menjalankan
panel:cachedapat tidak menghasilkan warning apa pun.
Gejalanya biasanya:
- Resource baru tidak muncul di sidebar;
- route baru 404;
- tidak ada error log.
Karena itu command harus berada di deploy script, bukan hanya runbook manual.
Rebuild tanpa full deploy
php artisan panel:clear
php artisan panel:cache2
Atau gunakan optimize:clear dan optimize.
Keduanya idempotent. panel:clear menganggap manifest yang memang sudah tidak ada sebagai success, sehingga aman dijalankan tanpa condition.
Hal yang perlu diperhatikan
- Shared
bootstrap/cachemerusak rollback. Ini adalah mistake paling mahal pada lifecycle Panel cache. - Tidak ada data user-specific yang dicache. Authorization, active navigation state, badge, record data, dan widget data dihitung ulang per request.
- Manifest menggunakan Panel id sebagai key. Mengganti Panel id membuat entry lama tidak cocok; Panel dapat fallback ke discovery sampai cache dibangun ulang.
- Malformed manifest diperlakukan seperti empty manifest. Jika required file tidak menghasilkan array, discovery fallback berjalan. Lebih lambat tetapi benar.
- Dua bentuk manifest lama/baru tetap dapat dibaca. Manifest sebelum fingerprint ditambahkan tetap bisa boot setelah upgrade.
panel:cachetidak mencache route. Jalankan route cache juga, atau gunakanphp artisan optimize.- Jangan commit
bootstrap/cache/panels.php. File dibuat per release dari code release tersebut.