1717use Illuminate \Support \Facades \Artisan ;
1818use Illuminate \Support \Facades \Context ;
1919use Illuminate \Support \Facades \DB ;
20+ use Illuminate \Support \Facades \Event ;
2021use Illuminate \Support \Facades \Log ;
2122use Illuminate \Support \Facades \Route ;
2223use Illuminate \Support \Facades \URL ;
2324use Laravel \Horizon \Horizon ;
2425use Laravel \Horizon \SystemProcessCounter ;
2526use Laravel \Horizon \WorkerCommandString ;
27+ use Laravel \Octane \Events \RequestTerminated ;
2628use Laravel \Passport \Client as PassportClient ;
2729use Lavary \Menu \Menu ;
2830use OpenApi \Analysers \AttributeAnnotationFactory ;
4951use ProcessMaker \Models ;
5052use ProcessMaker \Multitenancy \Tenant ;
5153use ProcessMaker \Observers ;
54+ use ProcessMaker \Octane \ResetRequestState ;
5255use ProcessMaker \PolicyExtension ;
5356use ProcessMaker \Providers \PermissionServiceProvider ;
5457use ProcessMaker \Repositories \SettingsConfigRepository ;
@@ -107,6 +110,9 @@ public function boot(): void
107110
108111 $ this ->checkConfigCache ();
109112
113+ // Register Octane listeners if Octane is enabled
114+ $ this ->registerOctaneListeners ();
115+
110116 // Hook after service providers boot
111117 self ::$ bootTime = (microtime (true ) - self ::$ bootStart ) * 1000 ; // Convert to milliseconds
112118 }
@@ -260,7 +266,7 @@ protected static function registerEvents(): void
260266 {
261267 // Listen to the events for our core screen
262268 // types and add our javascript
263- Facades \ Event::listen (ScreenBuilderStarting::class, function ($ event ) {
269+ Event::listen (ScreenBuilderStarting::class, function ($ event ) {
264270 // Add any extensions to form builder
265271 // and renderer from packages
266272 $ event ->manager ->addPackageScripts ($ event ->type );
@@ -279,7 +285,7 @@ protected static function registerEvents(): void
279285 });
280286
281287 // Log Notifications
282- Facades \ Event::listen (NotificationSent::class, function ($ event ) {
288+ Event::listen (NotificationSent::class, function ($ event ) {
283289 $ id = $ event ->notifiable ->id ;
284290 $ notifiable = get_class ($ event ->notifiable );
285291 $ notification = get_class ($ event ->notification );
@@ -288,24 +294,24 @@ protected static function registerEvents(): void
288294 });
289295
290296 // Log Broadcasts (messages sent to laravel-echo-server and redis)
291- Facades \ Event::listen (BroadcastNotificationCreated::class, function ($ event ) {
297+ Event::listen (BroadcastNotificationCreated::class, function ($ event ) {
292298 $ channels = implode (', ' , $ event ->broadcastOn ());
293299
294300 Log::debug ('Broadcasting Notification ' . $ event ->broadcastType () . 'on channel(s) ' . $ channels );
295301 });
296302
297303 // Fire job when task is assigned to a user
298- Facades \ Event::listen (ActivityAssigned::class, function ($ event ) {
304+ Event::listen (ActivityAssigned::class, function ($ event ) {
299305 $ task_id = $ event ->getProcessRequestToken ()->id ;
300306 // Dispatch the SmartInbox job with the processRequestToken as parameter
301307 SmartInbox::dispatch ($ task_id );
302308 });
303309
304- Facades \ Event::listen (MadeTenantCurrentEvent::class, function ($ event ) {
310+ Event::listen (MadeTenantCurrentEvent::class, function ($ event ) {
305311 event (new TenantResolved ($ event ->tenant ));
306312 });
307313
308- Facades \ Event::listen (TenantNotFoundForRequestEvent::class, function ($ event ) {
314+ Event::listen (TenantNotFoundForRequestEvent::class, function ($ event ) {
309315 if (config ('app.multitenancy ' ) === false || self ::actuallyRunningInConsole ()) {
310316 // This is expected if multitenancy is disabled.
311317 // We also need to check if we are running in a console command because
@@ -330,7 +336,7 @@ protected static function registerEvents(): void
330336 }
331337 });
332338
333- Facades \ Event::listen (function (CommandStarting $ event ) {
339+ Event::listen (function (CommandStarting $ event ) {
334340 if ($ event ->command === 'l5-swagger:generate ' ) {
335341 // Set the analyser to use the legacy DocBlockAnnotationFactory. This must
336342 // be set here because this config value is not serializable and cannot be cached.
@@ -511,6 +517,14 @@ public static function getBootTime(): ?float
511517 return self ::$ bootTime ;
512518 }
513519
520+ /**
521+ * Reset per-request query timing metrics.
522+ */
523+ public static function beginRequestTiming (): void
524+ {
525+ self ::$ queryTime = 0 ;
526+ }
527+
514528 /**
515529 * Get the query time for the request.
516530 *
@@ -568,6 +582,23 @@ public static function getPackageBootTiming(): array
568582 return self ::$ packageBootTiming ;
569583 }
570584
585+ /**
586+ * Reset per-request static state between Octane requests.
587+ *
588+ * Octane workers stay alive across requests, so static properties must be
589+ * cleared to avoid leaking data from one request into the next. Singletons
590+ * holding mutable state are handled by the 'flush' list in config/octane.php,
591+ * which Octane applies on its own.
592+ */
593+ private function registerOctaneListeners (): void
594+ {
595+ if (!class_exists (RequestTerminated::class)) {
596+ return ;
597+ }
598+
599+ Event::listen (RequestTerminated::class, ResetRequestState::class);
600+ }
601+
571602 /**
572603 * Find the tenant based on the environment variable
573604 */
0 commit comments