From f83b8b426aec3ca7eab8bccc047974a2e5d2e328 Mon Sep 17 00:00:00 2001 From: Ingo Schommer Date: Fri, 12 Jun 2020 16:39:40 +1200 Subject: [PATCH] FIX Resilient log handler implementation The log handler on QueuedJobService is triggering a write to the database on log messages. It's added to the *global logger singleton*, meaning it applies beyond the scope of this service execution. That's problematic when completely unrelated logic writes new log messages, and the buffer flushes - at the latest point, during PHP shutdown. At this point, a database is often no longer in a state to accept the write, e.g. during unit test execution. Note that a better fix would be to use a specific logger instance clone for this purpose, but we do want to inherit the log handlers set up for a specific project here, so can't just create a logger from scratch. --- src/Services/QueuedJobService.php | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/Services/QueuedJobService.php b/src/Services/QueuedJobService.php index a112be6b..5e72fef7 100644 --- a/src/Services/QueuedJobService.php +++ b/src/Services/QueuedJobService.php @@ -882,11 +882,6 @@ public function runJob($jobId) $this->extend('updateJobDescriptorAndJobOnException', $jobDescriptor, $job, $e); } - // Write any remaining batched messages at the end - if (isset($bufferHandler)) { - $bufferHandler->flush(); - } - ob_end_flush(); // now check the job state @@ -964,6 +959,24 @@ public function runJob($jobId) $this->handleBrokenJobException($jobDescriptor, $job, $e); $broken = true; } + + // Write any remaining batched messages at the end. + if ($logger instanceof Logger) { + foreach ($logger->getHandlers() as $handler) { + if ($handler instanceof BufferHandler) { + $handler->flush(); + } + } + } + + // If using a global singleton logger here, + // any messages added after this point will be auto-flushed on PHP shutdown through the handler. + // This causes a database write, and assumes the database and table will be available at this point. + if ($logger instanceof Logger) { + $logger->setHandlers(array_filter($logger->getHandlers(), function ($handler) { + return !($handler instanceof BufferHandler); + })); + } }); $this->unsetRunAsUser($runAsUser, $originalUser);