From cbf14e99bf64d890a74c1a8cbc926c51bad980f1 Mon Sep 17 00:00:00 2001 From: mscherer Date: Thu, 7 May 2026 00:14:48 +0200 Subject: [PATCH 1/2] Suppress idle-poll heartbeat unless verbose The worker loop printed three lines every sleeptime() interval on an idle queue: a timestamped "Looking for Job ...", "nothing to do, sleeping.", and a horizontal-rule separator. On a mostly-idle worker this fills logs and stdout with steady-state noise that conveys no information beyond "still alive". Gate those three lines behind the existing verbose flag so the default worker is silent on empty polls. Operators who want the per-iteration heartbeat keep it via -v / verbose. One-shot events ("nothing to do, exiting.", job start/finish, runtime termination, GC sweep) are not gated since they describe state changes rather than steady state. --- src/Queue/Processor.php | 10 ++++-- tests/TestCase/Queue/ProcessorTest.php | 46 ++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/src/Queue/Processor.php b/src/Queue/Processor.php index 0f50b647..ead711e5 100644 --- a/src/Queue/Processor.php +++ b/src/Queue/Processor.php @@ -228,8 +228,8 @@ public function run(array $args): int { if ($config['verbose']) { $this->log('run', $pid, false); + $this->io->out('[' . date('Y-m-d H:i:s') . '] Looking for Job ...'); } - $this->io->out('[' . date('Y-m-d H:i:s') . '] Looking for Job ...'); $queuedJob = $this->QueuedJobs->requestJob($this->getTaskConf(), $config['groups'], $config['types']); @@ -239,7 +239,9 @@ public function run(array $args): int { $this->io->out('nothing to do, exiting.'); $this->exit = true; } else { - $this->io->out('nothing to do, sleeping.'); + if ($config['verbose']) { + $this->io->out('nothing to do, sleeping.'); + } sleep(Config::sleeptime()); } @@ -256,7 +258,9 @@ public function run(array $args): int { // shutdown sweep is redundant. `cleanOldJobs()` stays — // that's about the queued_jobs table, not workers. } - $this->io->hr(); + if ($config['verbose']) { + $this->io->hr(); + } } $this->deletePid($pid); diff --git a/tests/TestCase/Queue/ProcessorTest.php b/tests/TestCase/Queue/ProcessorTest.php index c02155bf..32b36178 100644 --- a/tests/TestCase/Queue/ProcessorTest.php +++ b/tests/TestCase/Queue/ProcessorTest.php @@ -131,6 +131,52 @@ public function testRun() { $this->assertSame(CommandInterface::CODE_SUCCESS, $result); } + /** + * Without verbose, the idle-poll heartbeat ("Looking for Job ...", + * "nothing to do, sleeping.", and the trailing horizontal rule) must + * stay silent so a quiet queue doesn't spam stdout/log files. + * + * @return void + */ + public function testRunNonVerboseSuppressesIdlePollOutput() { + Configure::write('Queue.exitwhennothingtodo', true); + + $out = new ConsoleOutput(); + $err = new ConsoleOutput(); + $this->Processor = new Processor(new Io(new ConsoleIo($out, $err)), new NullLogger()); + + $result = $this->Processor->run([]); + + $this->assertSame(CommandInterface::CODE_SUCCESS, $result); + $output = $out->output(); + $this->assertStringNotContainsString('Looking for Job', $output); + $this->assertStringNotContainsString('nothing to do, sleeping', $output); + $this->assertStringNotContainsString("\n---", $output); + // One-shot exit event still fires: that's not steady-state noise. + $this->assertStringContainsString('nothing to do, exiting.', $output); + } + + /** + * Verbose mode keeps the existing per-iteration heartbeat so operators + * who opt in still see liveness output. + * + * @return void + */ + public function testRunVerboseShowsIdlePollOutput() { + Configure::write('Queue.exitwhennothingtodo', true); + + $out = new ConsoleOutput(); + $err = new ConsoleOutput(); + $this->Processor = new Processor(new Io(new ConsoleIo($out, $err)), new NullLogger()); + + $result = $this->Processor->run(['verbose' => true]); + + $this->assertSame(CommandInterface::CODE_SUCCESS, $result); + $output = $out->output(); + $this->assertStringContainsString('Looking for Job', $output); + $this->assertStringContainsString('nothing to do, exiting.', $output); + } + /** * Helper method for skipping tests that need a real connection. * From 4bd5cbe2213764186f50fa1440d8d42491dd74b6 Mon Sep 17 00:00:00 2001 From: mscherer Date: Thu, 7 May 2026 00:18:44 +0200 Subject: [PATCH 2/2] Update RunCommandTest assertions to event-based output testExecute and testServiceInjection asserted on "Looking for Job", which is now verbose-only steady-state output. Switch to the always-on event lines that prove the same thing: "terminating." for the empty- queue worker loop, and "Running Job of type \"Foo\"" for the job-execution path. --- tests/TestCase/Command/RunCommandTest.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/TestCase/Command/RunCommandTest.php b/tests/TestCase/Command/RunCommandTest.php index e18b091d..f2cef917 100644 --- a/tests/TestCase/Command/RunCommandTest.php +++ b/tests/TestCase/Command/RunCommandTest.php @@ -49,7 +49,9 @@ public function testExecute(): void { $this->exec('queue run'); $output = $this->_out->output(); - $this->assertStringContainsString('Looking for Job', $output); + // Worker loop ran to completion. The per-iteration heartbeat is + // verbose-only now, so assert on the always-on termination event. + $this->assertStringContainsString('terminating.', $output); $this->assertExitCode(0); } @@ -63,7 +65,7 @@ public function testServiceInjection(): void { $this->exec('queue run'); $output = $this->_out->output(); - $this->assertStringContainsString('Looking for Job', $output); + $this->assertStringContainsString('Running Job of type "Foo"', $output); $this->assertStringContainsString('CakePHP Foo Example.', $output); $this->assertStringContainsString('My TestService', $output); $this->assertExitCode(0);