
PHP
ã€ãã³ã

ãã¬ãžã³
æè¡ããã°
ã¯ãããŸããŠã5æã«M&Aã¯ã©ãŠããžå
¥ç€Ÿããã峯岞ã§ãã æ¢ã«1ã¶æãçµéããŸããããå
¥ç€Ÿãšã³ããªãæžããŠãããŸãã ãŸãã¯è»œãèªå·±ç޹ä»ãã ç¥å¥å·çåºèº«ã§ãæ°åããããã¯ãšã³ããšã³ãžãã¢ãšããŠåãå§ããçŸåš4幎ç®ã§ãã è¶£å³ã¯ã²ãŒã ã§ãã¢ã³ã¹ã¿ãŒãã³ã¿ãŒã®ãããªååãã¬ã€ãã§ããã²ãŒã ãç¹ã«å¥œãã æå€ãããããŸããããæãçŽãããŸã«ãããŸããå°åŠçã®é ã«ç±äžããŠããåæ®ã§ãä»ã§ã¯èšæ¶ããã©ããªããäœãããšãããçšåºŠã§ããã åè·ã«ã€ã㊠以åã¯ã€ãã³ãç³»ã®äŒç€Ÿã«3幎ã»ã©åšç±ããŠãããLaravelãCakePHPçã®PHPãã¬ãŒã ã¯ãŒã¯ãäž»ã«çšãããããã¯ãéçºã»æ¡ä»¶éçºãè¡ã£ãŠããŸãããâŠ
ã¯ããã« ããã«ã¡ã¯ããªããŒã«ããéçºéšå°å£²ã¢ããªããŒã ã®æ± ã§ãã æ¥åã§ Laravel Octane ã®ã¡ã¢ãªãæ®ãæåã«ã€ããŠèª¿æ»ããæ©äŒããããŸããã Laravel Octane ã¯ãé·æé皌åããããã»ã¹äžã§ Laravel ã¢ããªã±ãŒã·ã§ã³ãåãããŠé«éåããããŒã«ã§ãã䟿å©ãªäžæ¹ã§ãããã»ã¹ãé·ãçããããã¡ã¢ãªãæ®ãç¶ããæžãæ¹æ¬¡ç¬¬ã§ã¯ãªã¯ãšã¹ãéã§ç¶æ
ãåŒãç¶ãããŠããŸããšãããåŸæ¥ã® Nginx + PHP-FPM æ§æã® Laravel ã§ã¯çºçãã«ããç¹æ§ãæã£ãŠããŸãããã®ç¹æ§ãçè§£ããã«äœ¿ããšäºæããªãäºæ
ã«ã€ãªããå¯èœæ§ããããšæããŸããã ããã§æ¬èšäºã§ã¯ãOctane + Swoole ã®ä»çµã¿ãæŽçããäžã§ããµã³ãã«ããã°ã©ã ã§æåãæ€èšŒããWorker ããã»ã¹ãåžžé§ããããšã«èµ·å ããŠæ°ãã€ããã¹ããã€ã³ãã«ã€ããŠæŽçããããšæããŸãã Laravel ããã³ Octane ã«ã€ããŠå€å°ã®ç¥èãããæ¹ãåæã«æžããŠãããLaravel æ¬äœã®è§£èª¬çã«ã¯è§ŠããŸããã ãªããæ¬èšäºã®å
容ã¯äžæ¬¡æ
å ±ãã確èªããããã«åªããŠããŸãããç§ã®çè§£éãã Octane / Swoole ã®ããŒãžã§ã³å·®ã«ããæåã®éããå«ãŸããŠããå¯èœæ§ããããŸãã誀ã£ãŠå®è£
ãããšäºæ
ã«ã€ãªããåŸãé åã§ããããããæçµçã«ã¯ãèªèº«ã§ãœãŒã¹ã³ãŒããå
¬åŒããã¥ã¡ã³ããã確èªã®äžã§é©çšãã ããã ä»çµã¿ã®æŽç ãã®ç« ã§ã¯ãOctane + Swoole ã§åã®ãªã¯ãšã¹ãã®æ
å ±ãæ¬¡ã®ãªã¯ãšã¹ãã«æ®ãä»çµã¿ããæ¬¡ã® 4 ã€ã®èгç¹ããæŽçããŸãã Octane + Swoole ã§ã¯ Worker ããã»ã¹ãåžžé§ãããããPHP ããã»ã¹å
ã®ã¡ã¢ãªããªã¯ãšã¹ãããšã«åæåãããªã Octane ã¯ãªã¯ãšã¹ãããšã« $this->app ã clone ã㊠$sandbox äžã§åŠçããããšã§ãããŒã¹ã®ã¢ããªã€ã³ã¹ã¿ã³ã¹ãçŽæ¥æžãæããªãããã«ããŠãã ãã ã PHP ã® clone ã¯ã·ã£ããŒã³ããŒãªã®ã§ãå
±æããããªããžã§ã¯ãã®å
éšç¶æ
ã¯ãªã¯ãšã¹ãéã§æ®ãåŸã Octane 㯠RequestReceived ã€ãã³ãã«çŽã¥ããªã¹ããŒçŸ€ã§ãã¬ãŒã ã¯ãŒã¯åŽã®ç¶æ
ããªã»ããããŠãã æ¬èšäºã«ç»å Žããã¢ãŒããã¯ãã£å³ãã©ã€ããµã€ã¯ã«å³ã¯å¿
èŠãªèŠçŽ ã«çµã£ãŠç°¡ç¥åããŠããŸãã 1. Worker ããã»ã¹ãåžžé§ãããããã¡ã¢ãªã¯åæåãããªã Octane + Swoole ã¯ãé·æéçãã PHP ããã»ã¹ãç«ã¡äžããä»çµã¿ã§ãã Swoole ã®ããã»ã¹ã¢ãŒããã¯ã㣠Worker 㯠OS ããã»ã¹ã§ããManager ããè€æ°çæãããäžå®æ°ã®ãªã¯ãšã¹ããåŠçããã忢ã·ã°ãã«ãåä¿¡ãããŸã§èµ°ãç¶ããŸãã Worker ã®ã©ã€ããµã€ã¯ã« é·æéçãç¶ãã Worker ããã»ã¹ã¯æ¬¡ã®ããã«åããŸãã æ³šç®ãããã®ã¯ã1 ã€ã® Worker ããã»ã¹ãçãç¶ãããŸãŸè€æ°ã®ãªã¯ãšã¹ããé ã«åŠçãç¶ããæ§é ã§ããWorker èµ·åæã« 1 åã ã Laravel ã¢ããªã±ãŒã·ã§ã³ãçµã¿ç«ãŠãŠ $this->app ã«ä¿æãããã®åŸã¯ãªã¯ãšã¹ãã®ãã³ã«ãã® $this->app ã clone ã㊠$sandbox ãšããŠäœ¿ãåããŸãããã®ãåã $this->app ãè€æ°ãªã¯ãšã¹ãã«ãŸããã£ãŠäœ¿ããããç¹ããåŸã§èŠããåã®ãªã¯ãšã¹ãã®æ
å ±ãæ¬¡ã®ãªã¯ãšã¹ãã«æ®ã£ãŠããŸããä»çµã¿ã®äžéšã«ãªã£ãŠããŸãã Worker èµ·åæã« Laravel ã¢ããªã±ãŒã·ã§ã³ãçµã¿ç«ãŠãŠããåŠç Worker::boot() ã®å®è£
ã¯ä»¥äžã®éãã§ãã <?php // vendor/laravel/octane/src/Worker.php public function boot ( array $ initialInstances = []) : void { // ããŒã¹ãšãªã Laravel ã¢ããªã€ã³ã¹ã¿ã³ã¹ã1ã€çæ // 以éããªã¯ãšã¹ãã®ãã³ã«ãããã clone ãã $ this -> app = $ app = $ this -> appFactory -> createApplication ( ... ) ; $ this -> dispatchEvent ( $ app , new WorkerStarting ( $ app )) ; } ãªãã¡ã¢ãªãæ®ãã®ã Swoole + Octane ã§ã¯ä»¥äžã®ä»çµã¿ã§ã¡ã¢ãªãæ®ããŸãã Worker ããã»ã¹ãçãç¶ããããããªã¯ãšã¹ãçµäºæã«å€æ°ã»ãªããžã§ã¯ãã«å²ãåœãŠãããã¡ã¢ãªãè§£æŸãããªã çµæãšããŠã $this->app ãå«ã倿°ã»ãªããžã§ã¯ãããªã¯ãšã¹ãããŸããã§ã¡ã¢ãªã«æ®ãç¶ãã ããããå
ã¯ããã®ãã¡ã¢ãªã«æ®ãç¶ãã $this->app ããªã¯ãšã¹ãããšã«ã©ãæ±ããããšããããšã«çŠç¹ãåœãŠãŸãã 2. Octane ã¯ãªã¯ãšã¹ãããšã« $this->app ã clone ãã Worker ãåžžé§ããã° $this->app ãæ®ããŸãããã ããªã¯ãšã¹ãåŠçã®äžã§ $this->app ãçŽæ¥æžãæããŠããŸããšããã®å€æŽã次ã®ãªã¯ãšã¹ãã«ãã®ãŸãŸæ®ããŸããOctane ã¯ãããé¿ããããã«ããªã¯ãšã¹ãã®ãã³ã« $this->app ã clone ã㊠$sandbox ãäœãããã®äžã§ãªã¯ãšã¹ãåŠçãåãèšèšã«ãªã£ãŠããŸãã <?php // vendor/laravel/octane/src/Worker.php public function handle ( Request $ request , RequestContext $ context ) : void { // ã¢ããªã€ã³ã¹ã¿ã³ã¹ã clone ããŠãªã¯ãšã¹ãçšã® sandbox ãäœã CurrentApplication :: set ( $ sandbox = clone $ this -> app ) ; $ gateway = new ApplicationGateway ( $ this -> app, $ sandbox ) ; try { $ response = $ gateway -> handle ( $ request ) ; // ... ã¬ã¹ãã³ã¹è¿åŽ ... } finally { $ sandbox -> flush () ; // sandbox åŽã® bindings ã¯ãªã¢ unset ( $ gateway , $ sandbox , ... ) ; CurrentApplication :: set ( $ this -> app ) ; // å
ã®ã¢ããªã€ã³ã¹ã¿ã³ã¹ã«æ»ã } } ããã§ã® clone ã®åœ¹å²ã¯ããªã¯ãšã¹ãåŠçã $sandbox åŽã«éé¢ããŠãããŒã¹ã® $this->app ãçŽæ¥æžãæããªãããã«ããããšã§ãã $this->app èªäœã¯ Worker 寿åœãŸã§ãã£ãšçãç¶ããŸãããæ¯ãªã¯ãšã¹ãã®åŠçã $this->app ãçŽæ¥æžãæããªããã°ãçµæãšããŠããŒã¹ã倿Žããã«äœ¿ãåããããšããèšèšã«ãªã£ãŠããŸãã 3. clone ã¯ã·ã£ããŒã³ããŒãªã®ã§ãå
éšç¶æ
ã¯ãªã¯ãšã¹ãéã§æ®ãåŸã ãã ããPHP ã® clone ã¯ã·ã£ããŒã³ããŒã§ãããããåç¯ã®ãããŒã¹ãæžãæããªãããæãç«ã€ç¯å²ã«ã¯éçããããŸãã Application ãªããžã§ã¯ãèªäœã¯æ°èŠïŒãªã¯ãšã¹ãããšã®åšïŒ é
åããããã£ïŒ bindings / instances ãªã©ïŒã¯ã³ããŒãããïŒsandbox åŽã§æžãæããŠãå
ã«ã¯åæ ãããªãïŒ é
åã®äžèº«ïŒå®éã®ãªããžã§ã¯ãïŒã¯å
ã®ã¢ã㪠$this->app ãš $sandbox ã§å
±æããã ããã«ããã以äžã®ãããªæåã«ãªããŸãã äŸãã°ãªã¯ãšã¹ãäžã« app()->instance('request', $req) ã®ããã«å·®ãæ¿ããŠãã $sandbox åŽã«ã®ã¿åæ ãããããŒã¹ã® $this->app ã«ã¯åæ ãããªã äžæ¹ã§ãããŒã¹ã® $this->app ã«ç»é²ããã解決æžã¿ singleton ã€ã³ã¹ã¿ã³ã¹ã¯äž¡è
ã§å
±æããããŸãŸ ãsingleton ã«ãªã¯ãšã¹ãåºæããŒã¿ãå
¥ãããšæ¬¡ã®ãªã¯ãšã¹ãã«ãæ®ãããšããçŸè±¡ã¯ããã®ãclone ããŠããªããžã§ã¯ãèªäœã¯å
±æããããããšãèŠå ãšèããããŸãã clone ã¯ã³ã³ããã®é
åã¬ãã«ã§ã®éé¢ã¯æäŸãããã®ã®ãé
åã®äžã«å
¥ã£ãŠãããªããžã§ã¯ãã®å
éšç¶æ
ãŸã§ã¯å®ã£ãŠãããªãããšããã®ããã€ã³ãã§ãã 4. Octane ã® RequestReceived ãªã¹ããŒãäžéšã®ç¶æ
ããªã»ãããã clone ã ãã§ã¯é
åã®äžã«å
¥ã£ãŠãããªããžã§ã¯ãã®ããããã£æžãæããé²ããªããããOctane ã¯ãããããªã¯ãšã¹ãããšã«çºç«ããã€ãã³ããšããã«çŽã¥ããªã¹ããŒã§ãæç€ºçã«ç¶æ
ããªã»ããããããšã§è£ã£ãŠããŸãã Worker ã®ã¡ã€ã³ã«ãŒã Worker ã®ã¡ã€ã³ã«ãŒãã®äžã§ã¯ RequestReceived ã€ãã³ããçºç«ããããã©ã«ãã§ 8 åã®ãªã¹ããŒãé ã«å®è¡ããŠãã HTTP Kernel ã«åŠçãæž¡ããŸãã Worker èµ·å â WorkerStarting ã€ãã³ã â âââ ã¡ã€ã³ã«ãŒã ââââââââââââââââââââââââââââââââââââââââââ â RequestReceived ã€ãã³ã ââ [8 listeners] â â ââ FlushLocaleState â â ââ FlushQueuedCookies â â ââ FlushSessionState â â ââ FlushAuthenticationState â â ââ EnforceRequestScheme â â ââ EnsureRequestServerPortMatchesScheme â â ââ GiveNewRequestInstanceToApplication â â ââ GiveNewRequestInstanceToPaginator â â â â â HTTP Kernel (Middleware â Controller) â â â â â ãªã¯ãšã¹ãçµäº â âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ â max_requests ã«éããã Worker åèµ·å ããã 8 åã®ãªã¹ããŒã¯ãLocale / Cookie / Session / Auth ãšãã£ããã¬ãŒã ã¯ãŒã¯ç¶æ
ã®ãªã»ãããã app('request') ã®å·®ãæ¿ããHTTPS ã¹ããŒã ãããŒãã®æŽåæ§ãã§ãã¯ãªã©ãæ
ããŸãã å®è£
ã®äžã§ããç¹ã«æåãææ¡ããŠãããã 2 ã€ã確èªããŸãã ãŸããèªèšŒã¬ãŒããæ¯ãªã¯ãšã¹ãç Žæ£ãã FlushAuthenticationState ãèŠãŠã¿ãŸãã Laravel ã® AuthManager ã¯å
éšã§ Guard ã€ã³ã¹ã¿ã³ã¹ã $guards é
åã«ãã£ãã·ã¥ããå Guard ã¯ããã«èªèšŒæžã¿ãŠãŒã¶ãŒãããããã£ã«ä¿æããŸããOctane ã§ãã®ã€ã³ã¹ã¿ã³ã¹ãã¯ãªã¢ããªããšã singleton ã§èµ·ããçŸè±¡ãšåãæ§é ã§ãåã®ãªã¯ãšã¹ãã®èªèšŒãŠãŒã¶ãŒã次ã®ãªã¯ãšã¹ãã«åŒãç¶ãããŠããŸããŸãã FlushAuthenticationState ã¯ããã®ãã£ãã·ã¥ãæ¯ãªã¯ãšã¹ãç Žæ£ããããšã§ãåã®ãªã¯ãšã¹ãã®æ
å ±ãæ¬¡ã®ãªã¯ãšã¹ãã«æ®ããªãããã«ããŠããŸãã å®è£
ã¯ä»¥äžã®éãã§ãã <?php // vendor/laravel/octane/src/Listeners/FlushAuthenticationState.php class FlushAuthenticationState { public function handle ( $ event ) : void { if ( $ event -> sandbox -> resolved ( 'auth.driver' )) { $ event -> sandbox -> forgetInstance ( 'auth.driver' ) ; } if ( $ event -> sandbox -> resolved ( 'auth' )) { with ( $ event -> sandbox -> make ( 'auth' ) , function ( $ auth ) use ( $ event ) { $ auth -> setApplication ( $ event -> sandbox ) ; $ auth -> forgetGuards () ; }) ; } } } auth ãã³ã³ããã§è§£æ±ºæžã¿ã®å Žåã« forgetGuards() ãåŒã³ã ããGuards ã®ãã£ãã·ã¥ãã¯ãªã¢ããŠããããšãããããŸãã æ¬¡ã«ãRequest ã€ã³ã¹ã¿ã³ã¹ãå·®ãæ¿ãã GiveNewRequestInstanceToApplication ã®å®è£
ã¯ä»¥äžã®éãã§ãã <?php // vendor/laravel/octane/src/Listeners/GiveNewRequestInstanceToApplication.php class GiveNewRequestInstanceToApplication { public function handle ( $ event ) : void { $ event -> app -> instance ( 'request' , $ event -> request ) ; $ event -> sandbox -> instance ( 'request' , $ event -> request ) ; } } app('request') ãæ°ãã Request ã€ã³ã¹ã¿ã³ã¹ã«å·®ãæ¿ããŸãã app('request') ãåŒã¶ã³ãŒããåžžã«ææ°ã® Request ãèŠãããã®ã¯ããã®ãªã¹ããŒã®åãã«ãããã®ãšçè§£ã§ããŸãã äœãæ®ã£ãŠãäœãæ¶ããã®ã 2 ã€ã®ã¬ã€ã€ãŒã«åããŠæŽçããŸã ã¬ã€ã€ãŒ äœãåžžé§ããã ãªã»ããææ®µ Worker ããã»ã¹å
šäœ Worker ããã»ã¹èªäœ + 颿°ããŒãã« / ã¯ã©ã¹ããŒãã« / static 倿° / ã°ããŒãã«å€æ° octane:reload / max_request å°éã«ãã Worker åèµ·å Laravel Application ( $this->app ) bindingsãsingleton ã€ã³ã¹ã¿ã³ã¹ãboot æžã¿ ServiceProvider RequestReceived ãªã¹ããŒïŒéšåçïŒ ãªããå Worker ã¯ç¬ç«ãã OS ããã»ã¹ã§ãããããWorker éã®ã¡ã¢ãªã¯åé¢ãããŠããŸããã³ã«ãŒãã³ç¡å¹æã«ã¯åã Worker å
ã®ãªã¯ãšã¹ããé æ¬¡åŠçããããããæ°ã«ãã¹ãã¯ãåã Worker ã®äžã§ãåã®ãªã¯ãšã¹ãã®ããŒã¿ã次ã®ãªã¯ãšã¹ãã«åŒãç¶ãããŠããŸããªããããšããç¹ã«çµããããšèããããŸãã ãã®ããã§ãLaravel ã¢ããªã³ãŒãäžã§ãã䜿ãç¶æ
ä¿æã®æ¹æ³ããšã«ãåã Workerã»å¥ãªã¯ãšã¹ãã§ã©ãæ¯ãèãããæŽçãããšæ¬¡ã®ããã«ãªããŸãã ç¶æ
ä¿æã®æ¹æ³ å Workerã»å¥ãªã¯ãšã¹ã static 倿° æ®ã ã°ããŒãã«å€æ° / $GLOBALS æ®ã Worker boot æç¹ãªã©ã§è§£æ±ºæžã¿ã® singleton ã€ã³ã¹ã¿ã³ã¹ã®ãããã㣠æ®ã éåžž bind (æ¯åæ°èŠ) æ¯åæ°èŠ scoped ãã€ã³ãã£ã³ã° 次ã®ã©ã€ããµã€ã¯ã«éå§æã« flush $request->attributes Request èªäœãæ°èŠçæ ãæ®ãããšãªã£ãŠãã static / ã°ããŒãã«å€æ° / singleton ããããã£ã¯ããªã¯ãšã¹ãåºæã®ããŒã¿ãããªã¯ãšã¹ãããšã«å¢ãç¶ããããŒã¿ã眮ããšäºæ
ã«ã€ãªããåŸãç¹ã«æ³šæãå¿
èŠã§ããã¢ããªèµ·åæã« 1 床ã ãåæåããããããªäžå€ãªããŒã¿ããWorker å
ã§æå³çã«å
±æãããããŒã¿ã眮ãåã«ã¯åé¡ãªããšèããŠããŸãã ãããŸã§ã¯ä»æ§äžãããªã£ãŠããã¯ãããšããæŽçã§ãããæ¬¡ã¯ç°¡æçãªããã°ã©ã ã§åäœãæ€èšŒããŸãã æ€èšŒ ä»çµã¿ã®æŽçã§ç€ºãã芳ç¹ãã宿©ã§é ã«ç¢ºèªããŠãããŸãã static 倿° / ã°ããŒãã«å€æ°ããªã¯ãšã¹ãéã§æ®ãããš $this->app ã®å
éšç¶æ
ïŒsingleton ã€ã³ã¹ã¿ã³ã¹ã®ããããã£ïŒããªã¯ãšã¹ãéã§æ®ãããš RequestReceived ãªã¹ããŒãäžéšã®ç¶æ
ãå®éã«ãªã»ããããããš å ããŠããããã®æ€èšŒãæç«ããåæãšããŠãå Worker å
ã§ã¯ãªã¯ãšã¹ããé æ¬¡åŠçããããããšãæåã«ç¢ºèªããŸãã æ€èšŒç°å¢ æ€èšŒã¯ macOS äžã®ããŒã«ã« Docker ã³ã³ããã§ã以äžã®ããŒãžã§ã³æ§æã§è¡ããŸãã ãœãããŠã§ã¢ ããŒãžã§ã³ Laravel 12.59.0 Octane 2.17.3 Swoole 6.2.1 Octane ã¯æ¬¡ã®ã³ãã³ãã§èµ·åããŸãã php artisan octane:start --server=swoole --workers=10 --max-requests=500 ãã®ãšãå
éšã§é©çšããã䞻㪠Swoole ãªãã·ã§ã³ã¯æ¬¡ã®éãã§ãã èšå® å€ ç±æ¥ enable_coroutine false Octane ããã©ã«ãïŒLaravel æ¬äœãã³ã«ãŒãã³ã»ãŒãã§ãªãããæå³çã«ç¡å¹åïŒ worker_num 10 --workers=10 ã§æå® max_request 500 --max-requests=500 ã§æå®ïŒã¡ã¢ãªãªãŒã¯å¯ŸçïŒ ç¹å¥ãªèšå®ã¯ããŠããããOctane / Swoole ã®ããã©ã«ãã®ãŸãŸã§ãã æ€èšŒçšã«ãŒã㯠routes/web.php ã«çšæããcurl ã§å©ããŠçµæã芳å¯ããŸãã åæã®ç¢ºèª: å Worker å
ã§ãªã¯ãšã¹ããé æ¬¡åŠçãããããš ãŸã倧åæãšããŠã1 Worker å
ã§ã¯è€æ°ãªã¯ãšã¹ãã䞊è¡åŠçãããã1 ã€ãã€é çªã«åŠçãããããšã確èªããŸãããã以éã®æ€èšŒã¯ãã¹ãŠãåã Worker ã«æ¥ãè€æ°ãªã¯ãšã¹ããé çªã«åŠçãããããšããåæã§è°è«ãçµã¿ç«ãŠãããã確èªããŸãã 確èªçšã³ãŒã ãªã¯ãšã¹ããåãåã£ãã 2 ç§ã¹ãªãŒãã㊠PID ãšã³ã«ãŒãã³ ID ãè¿ãã ãã®åçŽãªã«ãŒããçšæããŸãã <?php Route :: get ( '/test-coroutine' , function () { $ pid = getmypid () ; $ cid = \Swoole\Coroutine :: getCid () ; sleep ( 2 ) ; return [ 'pid' => $ pid , 'cid' => $ cid , 'is_coroutine' => $ cid !== - 1 , ] ; }) ; å®è¡ Worker æ°ã 1 ã«çµã£ãç¶æ
ïŒ --workers=1 ïŒã§ã3 ãªã¯ãšã¹ãã䞊åã§æããŸãããã䞊è¡åŠçããããªãåèš 2 ç§ååŸã§å®äºããã¯ãã§ãã start= $( date +%s ) curl -s http://localhost:8001/test-coroutine > /tmp/r1 & curl -s http://localhost:8001/test-coroutine > /tmp/r2 & curl -s http://localhost:8001/test-coroutine > /tmp/r3 & wait echo " Total: $(( $ ( date +%s ) - start )) s " çµæ { " pid ": 14 ," cid ": -1 ," is_coroutine ": false } { " pid ": 14 ," cid ": -1 ," is_coroutine ": false } { " pid ": 14 ," cid ": -1 ," is_coroutine ": false } Total : 6s 3 ãªã¯ãšã¹ãã® PID ãäžèŽïŒ=14ïŒãã cid = -1 ã§ã³ã«ãŒãã³å€ãåèšæéã 2 ç§Ã3 ïŒ 6 ç§ãšãªã£ãŠããããšããã1 Worker å
ã§ã¯ãªã¯ãšã¹ãã䞊è¡ã§ã¯ãªãé æ¬¡åŠçãããããšã確èªã§ããŸããã æ€èšŒ 1: static 倿° / ã°ããŒãã«å€æ°ããªã¯ãšã¹ãéã§æ®ãããš ä»çµã¿ã®æŽçã§ãstatic 倿°ã¯å Worker å
ã§ã¯æç¶ããããšæžããŸããããããå®éã«ç¢ºãããŸãã 確èªçšã³ãŒã <?php Route :: get ( '/test-static' , function () { static $ counter = 0 ; $ counter ++ ; $ GLOBALS [ 'global_counter' ] = ( $ GLOBALS [ 'global_counter' ] ?? 0 ) + 1 ; return [ 'pid' => getmypid () , 'static_counter' => $ counter , 'global_counter' => $ GLOBALS [ 'global_counter' ] , ] ; }) ; static 倿°ãšã°ããŒãã«å€æ°ã®äž¡æ¹ãã€ã³ã¯ãªã¡ã³ãããã·ã³ãã«ãªã³ãŒãã§ãã å®è¡ ãŸããå Worker å
æåãèŠããã Worker æ° 1ïŒ --workers=1 ïŒã§é 次 10 ãªã¯ãšã¹ããæããŸãã for i in { 1 .. 10 } ; do curl -s http://localhost:8001/test-static echo done 次ã«ãWorker æ° 10ïŒ --workers=10 ïŒã§äžŠå 20 ãªã¯ãšã¹ããæããWorker éã®ç¬ç«æ§ã確èªããŸãã for i in { 1 .. 20 } ; do curl -s http://localhost:8001/test-static > /tmp/s_ $i & done wait for i in { 1 .. 20 } ; do cat /tmp/s_ $i ; echo; done | sort çµæ é æ¬¡ 10 ãªã¯ãšã¹ãïŒ --workers=1 ïŒïŒ { " pid ": 14 ," static_counter ": 1 ," global_counter ": 1 } { " pid ": 14 ," static_counter ": 2 ," global_counter ": 2 } { " pid ": 14 ," static_counter ": 3 ," global_counter ": 3 } ... { " pid ": 14 ," static_counter ": 10 ," global_counter ": 10 } 䞊å 20 ãªã¯ãšã¹ãïŒ --workers=10 ïŒïŒ { " pid ": 22 ," static_counter ": 1 ," global_counter ": 1 } { " pid ": 22 ," static_counter ": 2 ," global_counter ": 2 } { " pid ": 23 ," static_counter ": 1 ," global_counter ": 1 } { " pid ": 23 ," static_counter ": 2 ," global_counter ": 2 } { " pid ": 24 ," static_counter ": 1 ," global_counter ": 1 } { " pid ": 24 ," static_counter ": 2 ," global_counter ": 2 } ... { " pid ": 31 ," static_counter ": 1 ," global_counter ": 1 } { " pid ": 31 ," static_counter ": 2 ," global_counter ": 2 } é æ¬¡ 10 ãªã¯ãšã¹ãã§ã¯å
šãŠåã PIDïŒ=14ïŒã§ã static_counter ãš global_counter ã 1 ãã 10 ãŸã§é£ç¶ããŠå¢å ããŠããŸããå Worker å
ã§ã¯ static / ã°ããŒãã«å€æ°ãæç¶ããŠããããšã確èªã§ããŸã 䞊å 20 ãªã¯ãšã¹ãã§ã¯ 10 åã®ç°ãªã PIDïŒ22 ã 31ïŒã«ãªã¯ãšã¹ãã忣ããããããã® Worker ã§ã«ãŠã³ã¿ãç¬ç«ã« 1 ããå§ãŸã£ãŠããŸããWorker éã§ã¡ã¢ãªãåé¢ãããŠããããšãåãããŸã 以äžããã static 倿°ãšã°ããŒãã«å€æ°ã¯å Worker å
ã®ãªã¯ãšã¹ãéã§æç¶ããWorker éã§ã¯åé¢ãããããšã確èªã§ããŸããã ããã¯ã1 ãªã¯ãšã¹ãç®ã®å€ã 2 ãªã¯ãšã¹ãç®ã«æå³ããèŠããŠããŸãå¯èœæ§ãæå³ããŸããåã®ãªã¯ãšã¹ãã®æ
å ±ãæ¬¡ã®ãªã¯ãšã¹ãã«æ®ããã¿ãŒã³ãšèãããããããå©çšã«ã¯æ³šæãå¿
èŠããã§ãã æ€èšŒ 2: $this->app ã®å
éšç¶æ
ããªã¯ãšã¹ãéã§æ®ãããš singleton ã®äžã«ãªã¯ãšã¹ãåºæã®ããŒã¿ãä¿æããŠããªã¯ãšã¹ãéã§å€ãæ®ãããšã確èªããŸãã 確èªçšã³ãŒã <?php // app/Services/UserContextSingletonService.php class UserContextSingletonService { private ? string $ currentUserName = null ; public function setCurrentUser ( string $ name ) : void { $ this -> currentUserName = $ name ; } public function getCurrentUser () : ? string { return $ this -> currentUserName; } } <?php // app/Providers/AppServiceProvider.php public function register () : void { $ this -> app -> singleton ( UserContextSingletonService :: class ) ; } public function boot () : void { // ããŒã¹ã® $this->app->instances ã«ã€ã³ã¹ã¿ã³ã¹ãæ ŒçŽãããããboot æç¹ã§ resolve ãã $ this -> app -> make ( UserContextSingletonService :: class ) ; } éåžžã® singleton() ã ãã§ã¯ãåå app(...) 解決æã«ã€ã³ã¹ã¿ã³ã¹ã sandbox åŽã«å
¥ãããªã¯ãšã¹ãçµäºæã® $sandbox->flush() ã§ç Žæ£ãããŸãããªã¯ãšã¹ãéã§æç¶ããç¶æ
ãåçŸããããããµã³ãã«ã§ã¯ boot() ã§ make() ãåŒãã§ããŒã¹ã® $this->app->instances ã«ã€ã³ã¹ã¿ã³ã¹ãç©ãã§ããŸãã <?php use App\Services\UserContextSingletonService; Route :: get ( '/test-singleton-set/{name}' , function ( string $ name ) { app ( UserContextSingletonService :: class ) -> setCurrentUser ( $ name ) ; return [ 'pid' => getmypid () , 'action' => 'SET' , 'value' => app ( UserContextSingletonService :: class ) -> getCurrentUser () , ] ; }) ; Route :: get ( '/test-singleton-get' , function () { return [ 'pid' => getmypid () , 'action' => 'GET' , 'value' => app ( UserContextSingletonService :: class ) -> getCurrentUser () , ] ; }) ; å®è¡ curl http://localhost:8001/test-singleton-set/Alice curl http://localhost:8001/test-singleton-get curl http://localhost:8001/test-singleton-get çµæ { " pid ": 14 ," action ":" SET "," value ":" Alice " } { " pid ": 14 ," action ":" GET "," value ":" Alice " } â å¥ãªã¯ãšã¹ããªã®ã«æ®ã£ãŠãã { " pid ": 14 ," action ":" GET "," value ":" Alice " } â ãŸã æ®ã£ãŠãã å¥ã®ãªã¯ãšã¹ãã«ãããããããAlice ãšããå€ããã®ãŸãŸèŠããŠããŸãã singleton ãã€ã³ãã£ã³ã°ã®ã€ã³ã¹ã¿ã³ã¹ããããã£ã«æ ŒçŽããå€ãæ®ãããšã確èªã§ããŸããã æ€èšŒ 3: RequestReceived ãªã¹ããŒãäžéšã®ç¶æ
ããªã»ããããããš FlushAuthenticationState ãªã¹ããŒã Guard ãã£ãã·ã¥ãç Žæ£ããŠããããšã確ãããŸãã 確èªçšã³ãŒã <?php use App\Models\User; use Illuminate\Support\Facades\Auth; Route :: get ( '/test-auth-set/{name}' , function ( string $ name ) { $ user = new User ([ 'name' => $ name ]) ; Auth :: setUser ( $ user ) ; return [ 'pid' => getmypid () , 'action' => 'SET' , 'user_name' => Auth :: user () ?-> name , ] ; }) ; Route :: get ( '/test-auth-get' , function () { return [ 'pid' => getmypid () , 'action' => 'GET' , 'user_name' => Auth :: user () ?-> name , ] ; }) ; Auth::setUser() ãå©çšããŠããã©ã«ãã® Guardã® $user ããããã£ã«çŽæ¥ User ã€ã³ã¹ã¿ã³ã¹ãå
¥ããGuard ãã£ãã·ã¥ã®ç¶æ
ãäœã£ãŠæ€èšŒããŸãã å®è¡ (1) ããã©ã«ãæ§æïŒ FlushAuthenticationState æå¹ïŒ curl http://localhost:8001/test-auth-set/Alice curl http://localhost:8001/test-auth-get çµæã¯ä»¥äžã®éãã§ãã { " pid ": 14 ," action ":" SET "," user_name ":" Alice " } { " pid ": 14 ," action ":" GET "," user_name ": null } â flush ã§æ¶ããŠãã å®è¡ (2) FlushAuthenticationState ãå€ããå Žå æ€èšŒã®ããã RequestReceived ãªã¹ããŒãã FlushAuthenticationState ãé€å€ããŸãã <?php // config/octane.php ïŒlisteners éšåã®ã¿æç²ïŒ use Laravel\Octane\Events\RequestReceived; use Laravel\Octane\Listeners\FlushAuthenticationState; use Laravel\Octane\Octane; return [ // ... 'listeners' => [ // ... RequestReceived :: class => array_values ( array_filter ( Octane :: prepareApplicationForNextRequest () , fn ( $ listener ) => $ listener !== FlushAuthenticationState :: class , )) , // ... ] , ] ; åã curl ãå®è¡ããŸãã { " pid ": 15 ," action ":" SET "," user_name ":" Alice " } { " pid ": 15 ," action ":" GET "," user_name ":" Alice " } â åã®ãªã¯ãšã¹ãã®æ
å ±ãæ®ã£ãŠãã ãªã¯ãšã¹ãããŸããã§ Alice ãšããå€ãæ®ã£ãŠããŸãã æ€èšŒçµæããã FlushAuthenticationState ãå€ããšèªèšŒç¶æ
ããªã¯ãšã¹ãéã§æ®ããæå¹ãªå Žå㯠Guard ãã£ãã·ã¥ãæ¯ãªã¯ãšã¹ãç Žæ£ãããããšã確èªã§ããŸããããã¬ãŒã ã¯ãŒã¯æšæºã® Auth ã Octane ã§ãå®å
šã«äœ¿ããã®ã¯ããã®ãªã¹ããŒãè£ã§åããŠããããããã ãšèšããŸãã ãããã« æ¬èšäºã§ã¯ãOctane + Swoole ã§åã®ãªã¯ãšã¹ãã®æ
å ±ãæ¬¡ã®ãªã¯ãšã¹ãã«æ®ãä»çµã¿ãæŽçãããµã³ãã«ã³ãŒãã§åäœãæ€èšŒããŸããããã®çµæã clone ãšãªã¹ããŒã«ãã£ãŠ Auth ãªã©ã®ãã¬ãŒã ã¯ãŒã¯åŽã®ç¶æ
ã¯ãªã¯ãšã¹ãããšã«ã¯ãªã¢ãããäžæ¹ã static 倿° / ã°ããŒãã«å€æ°ããWorker boot æã«è§£æ±ºæžã¿ã® singleton ã€ã³ã¹ã¿ã³ã¹ã®ããããã£ã¯èªåã§ã¯ã¯ãªã¢ãããªãããšã確èªã§ããŸããã æç¶ãããŠã¯ãããªãå Žæã«ç¶æ
ã眮ããªãããšããŸããããç¬èªã®ã°ããŒãã«ç¶æ
ãæãããå Žåã«ã¯ RequestReceived ãªã©ã®ã€ãã³ãã«èªåã®ãªã¹ããŒã远å ããŠã¯ãªã¢ããããšãæèã§ããã°ãšæããŸãã æåŸãŸã§èªãã§ããã ãããããšãããããŸããã åè Deep Dive into Laravel OctaneïŒAlbert ChenïŒ
ã¯ããã« 2026幎5æ14-15æ¥(æšé)ã«åå€å±ã®äžæ¥ããŒã«&ã«ã³ãã¡ã¬ã³ã¹ã«ãŠã¯ã©ãŠããã€ãã£ãäŒè°ãéå¬ãããŸãããæ¬èšäºã§ã¯åã€ãã³ãã§è¡ãããçºè¡šã®äžããããããã€ã³ã¿ãŒãããç ç©¶æã®å°ç°ç¥å€®ãã(@ […]














