Octane
Pada Laravel Octane, application melakukan boot satu kali lalu worker tetap hidup untuk menangani banyak request. Artinya state yang tertinggal dari satu request berpotensi masih ada pada request berikutnya. PandaBear dirancang untuk kondisi ini: current Panel, parent record, dan current Tenant semuanya disimpan pada scoped container binding, dan tidak ada request state yang disimpan pada static property. Gunakan halaman ini ketika menjalankan PandaBear di Swoole, RoadRunner, atau FrankenPHP, atau ketika Anda mencurigai ada state Panel yang bocor antar-request.
Contoh minimal yang berfungsi
php artisan octane:start --workers=4Pada setiap deploy, setelah cache dibangun ulang:
php artisan optimize
php artisan octane:reload2
Tidak ada konfigurasi PandaBear khusus yang perlu diaktifkan untuk Octane. Bagian berikut menjelaskan mengapa, serta satu setting yang dapat merusak isolation jika dimatikan tanpa pengganti.
Lokasi request state
use PandaPanel\Support\PanelContext;
// PandaPanelServiceProvider::register()
$this->app->scoped(PanelContext::class);2
3
4
scoped adalah lifecycle binding yang dibersihkan Octane di antara request. Semua keputusan yang hanya berlaku untuk satu request disimpan di sini:
| Method | Signature | Menyimpan |
|---|---|---|
setPanel | setPanel(?Panel $panel): void | Panel yang di-resolve request ini |
panel | panel(): ?Panel | current Panel |
hasPanel | hasPanel(): bool | apakah current Panel tersedia |
set | set(string $key, mixed $value): void | generic context bag — digunakan tenancy dan parent record |
get | get(string $key, mixed $default = null): mixed | membaca context bag |
forget | forget(): void | membersihkan Panel dan seluruh bag |
use PandaPanel\Support\PanelContext;
$context = app(PanelContext::class);
$context->hasPanel(); // false di luar request Panel
$context->get('tenant'); // null sampai ResolveTenant melakukan bind2
3
4
5
6
Tidak ada state di atas yang static. Inilah yang mencegah current Panel bocor antar-request dan antar-test.
PandaPanel\Core\PanelManager::setCurrentPanel() dan currentPanel() hanyalah wrapper terhadap object context yang sama. Console command atau job yang mengatur current Panel juga menulis ke scoped context tersebut.
PandaPanel\Tenancy\Tenancy menyimpan Tenant dengan key:
panel.tenantpada bag yang sama, dengan alasan yang sama.
Middleware yang menegakkan isolation
// PandaPanelServiceProvider::WEB_MIDDLEWARE
ResetPanelContext::class,
RedirectPanelHome::class,
ShareFlashToast::class,
SharePanelData::class,2
3
4
5
ResetPanelContext memanggil PanelContext::forget() di awal setiap web request. Middleware ini dipasang pada seluruh group web, bukan hanya route group PandaBear:
public function handle(Request $request, Closure $next): Response
{
$this->context->forget();
return $next($request);
}2
3
4
5
6
ResolvePanel hanya berjalan pada Panel route. Tanpa reset global, request non-Panel yang datang setelah request Panel dapat masih melihat current Panel lama. Pada PHP-FPM biasa masalah tersebut sulit terlihat karena container dibuat ulang setiap request; pada Octane worker tetap hidup sehingga leak menjadi nyata.
Dengan reset pada seluruh web group, invariant berikut selalu benar:
Di luar request Panel, tidak ada current Panel.
Setting yang paling penting di Octane
// config/panda-panel.php
'register_web_middleware' => true, // biarkan aktif2
Mematikannya tanpa mendaftarkan ResetPanelContext sendiri di bootstrap/app.php adalah cara paling langsung membuat Panel state bertahan melewati request boundary.
State yang memang boleh persisten
Binding berikut adalah singleton dan sengaja hidup sepanjang worker. Semua menyimpan configuration, bukan request state:
| Binding | Menyimpan |
|---|---|
PandaPanel\Core\PanelRegistry | object Panel yang terdaftar |
PandaPanel\Core\PanelManager | registry Resource/Page/Widget/Navigation per Panel — terutama class name |
PandaPanel\Discovery\PanelDiscoverer | stateless |
PandaPanel\Cache\PanelManifest | manifest yang sudah dibaca |
PandaPanel\Support\NavigationBuilder | tidak menyimpan state user; visibility/active state dihitung ulang setiap call |
PandaPanel\Routing\PanelRouteRegistrar | router dan manager |
Registry Panel adalah daftar class name, dan class name sama untuk seluruh user. Yang tidak boleh disimpan di singleton/static adalah:
- authorization result;
- active navigation state;
- badge value;
- record data;
- widget data.
Semua hal tersebut dihitung ulang per request.
Empat static yang memang ada di package
Keempatnya aman karena tidak menyimpan request/user state.
PSR-4 prefix map
// PandaPanel\Discovery\ClassResolver
private static ?array $prefixes = null;2
Ini adalah Composer PSR-4 map yang di-memoize sepanjang process. Map tersebut bersifat read-only setelah dibaca dan tidak berubah tanpa process/autoloader baru.
Missing policy notice cache
// PandaPanel\Support\MissingPolicyNotice
private static array $reported = [];2
Menandai model mana yang sudah pernah dilaporkan tidak memiliki policy agar satu missing policy tidak menghasilkan log pada setiap navigation build.
Notice ini development-only dan hanya menyimpan class name, bukan data user.
use PandaPanel\Support\MissingPolicyNotice;
MissingPolicyNotice::forget(); // hanya untuk test2
3
Resource integration settings
// PandaPanel\Resources\Resource
private static array $integrationSettings = [];2
Resolved Integrations object di-memoize per Resource class:
self::$integrationSettings[static::class] ??= static::integrations(...)Yang disimpan adalah deklarasi configuration Resource yang identik untuk seluruh user/request.
Registered integration observers
// PandaPanel\Integrations\IntegrationObserver
private static array $registered = [];2
Menandai kombinasi model|panel|resource yang sudah memasang Eloquent listener agar model yang sama pada dua Panel tidak mendaftarkan listener dua kali dan mengirim integration dua kali.
Yang disimpan hanya key, bukan record. IntegrationObserver::forget() tersedia untuk test.
Manifest di dalam Octane worker
PanelManifest membaca bootstrap/cache/panels.php satu kali lalu menyimpan parsed array pada instance. Worker yang sudah membacanya terus menggunakan copy tersebut sampai process direcycle.
php artisan panel:clear # menghapus file; tidak mengubah worker yang sudah hidup
php artisan octane:reload # merecycle worker agar membaca ulang2
clear() memang juga melupakan in-memory copy pada process tempat method itu dijalankan. Tetapi CLI dan Octane worker adalah process berbeda. Karena itu panel:clear melalui CLI tidak dapat menyentuh memory worker yang sudah berjalan.
Keuntungannya adalah performa yang memang menjadi tujuan Octane: dengan manifest tersedia, request tidak melakukan filesystem discovery. Pada worker yang sudah boot, tidak ada provider boot ulang dan tidak ada route registration ulang per request.
Urutan deploy
composer install --no-dev --optimize-autoloader
php artisan migrate --force
npm ci && npm run build
php artisan optimize # config, routes, events, views — dan panel:cache
php artisan octane:reload # worker membaca code + manifest baru
php artisan queue:restart # long-lived process lain2
3
4
5
6
octane:reload harus dilakukan setelah optimize. Jika worker direload terlalu awal, worker baru dapat hidup dengan cache release sebelumnya.
Development mode berbeda. octane:start --watch merecycle worker ketika file berubah. Menggunakan Panel cache di local development dapat membingungkan: class baru sudah dilihat watcher, tetapi manifest lama masih tidak mencantumkannya. Karena itu jangan gunakan cached Panel manifest untuk workflow development biasa.
Memory
Dua operasi synchronous PandaBear memiliki batas chunk:
| Operasi | Dibatas oleh | Default |
|---|---|---|
| Synchronous export | Exporter::chunkSize() | 500 record per chunk |
| Synchronous import | Importer::chunkSize() | 200 row per chunk |
Operasi yang lebih besar dapat dialihkan ke queue berdasarkan threshold:
use PandaPanel\Actions\Exports\Exporter;
Exporter::queueAfter(); // 2000 records2
3
Pada Octane, alasan meng-queue pekerjaan besar lebih kuat dibanding FPM. Request yang mencapai peak memory sangat besar dapat meninggalkan worker dengan footprint besar sepanjang lifecycle worker tersebut.
Menurunkan queueAfter() adalah cara paling sederhana menjaga operasi besar keluar dari process request. Lihat Queues.
Yang tidak diklaim framework
PandaBear tidak menjalankan Octane-specific CI matrix. Yang diuji adalah invariant yang dibutuhkan Octane:
Request state tidak disimpan pada static dan dapat dibersihkan.
Compatibility matrix mendokumentasikan constraint desain ini dan test suite menguji context isolation secara langsung:
it('keeps context out of static state so it cannot leak between requests', function (): void {
$context = app(PanelContext::class);
$context->setPanel(app(PanelManager::class)->get('admin'));
$context->forget();
expect($context->hasPanel())->toBeFalse();
});2
3
4
5
6
7
8
Jika application Anda menggunakan Octane, tetap jalankan suite application sendiri di environment Octane. Resource, service, plugin, atau custom code application juga harus mengikuti aturan yang sama.
Aturan untuk custom Panel code
- Jangan memoize hasil yang bergantung pada user ke static property.
canViewAny(), navigation badge, Table query, dan permission result semuanya per-user. - Jangan memoize current Panel. Gunakan
PanelManager::currentPanel()setiap kali dibutuhkan; read tersebut murah dan scoped. - Static property pada
Resourceaman jika isinya configuration.$slug,$label,$navigationIconmendeskripsikan class, bukan request. - Queued job berada di luar request context. Job harus memilih Panel sendiri dan, jika tenancy digunakan, masuk ke Tenant context secara eksplisit.
Hal yang perlu diperhatikan
panel:cleardari CLI tidak mengubah worker yang sedang berjalan. Lakukan reload worker.register_web_middleware => falsetanpa memasangResetPanelContextsendiri adalah state leak. Gejalanya dapat berupa route non-Panel yang melihat current Panel dari request sebelumnya.- Cached manifest bersama
octane:start --watchdapat membingungkan. Worker reload melihat source baru tetapi manifest lama tetap tidak mengenal class tersebut. - Octane menjaga opcache panas antar-request, bukan antar-deploy. Perlakukan manifest seperti PHP cache file lain dan ikuti strategi opcache application.
- Synchronous export besar dapat mempertahankan peak memory worker. Queue-kan pekerjaan besar.