From 8d59bac8279e467f5c75210859dfc7256dae70be Mon Sep 17 00:00:00 2001 From: Marc Bischof Date: Mon, 23 Feb 2026 12:10:37 +0100 Subject: [PATCH] Add visibility timeout validation and update dequeue logic --- Classes/Queue/AzureQueueStorage.php | 17 ++++++++++++--- Tests/Unit/Queue/AzureStorageQueueTest.php | 24 ++++++++++++++++++++++ 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/Classes/Queue/AzureQueueStorage.php b/Classes/Queue/AzureQueueStorage.php index 675177d..ff21986 100644 --- a/Classes/Queue/AzureQueueStorage.php +++ b/Classes/Queue/AzureQueueStorage.php @@ -127,6 +127,7 @@ public function __construct(string $name, array $options = []) // Store other configuration $this->defaultTimeout = (int)($options['defaultTimeout'] ?? 30); + $this->visibilityTimeout = (int)($options['visibilityTimeout'] ?? 300); $this->claimCheckThreshold = (int)($options['claimCheckThreshold'] ?? 32768); $this->defaultTtl = (int)($options['defaultTtl'] ?? 604800); $this->pollingInterval = (int)($options['pollingInterval'] ?? 1000); @@ -625,6 +626,14 @@ protected function validateOptions(array $options): void throw new JobQueueException('Azure Storage connection string is required', 1234567890); } + $visibilityTimeout = (int)($options['visibilityTimeout'] ?? 300); + if ($visibilityTimeout < 1 || $visibilityTimeout > 604800) { + throw new JobQueueException( + 'visibilityTimeout must be between 1 and 604800 seconds.', + 1234567926 + ); + } + if (isset($options['usePriorityQueue']) && $options['usePriorityQueue']) { $suffix = $options['prioritySuffix'] ?? $this->prioritySuffix; $maxBaseNameLength = 63 - strlen($suffix); @@ -676,14 +685,16 @@ protected function receiveMessage(?int $timeout = null): ?AzureQueueStorageMessa $startTime = microtime(true); - while ((microtime(true) - $startTime) < $timeout) { + do { $message = $this->tryReceiveOnce(); if ($message !== null) { return $message; } - usleep($this->pollingInterval * 1000); - } + if ((microtime(true) - $startTime) < $timeout) { + usleep($this->pollingInterval * 1000); + } + } while ((microtime(true) - $startTime) < $timeout); return null; } diff --git a/Tests/Unit/Queue/AzureStorageQueueTest.php b/Tests/Unit/Queue/AzureStorageQueueTest.php index d2b8e3e..1618ae7 100644 --- a/Tests/Unit/Queue/AzureStorageQueueTest.php +++ b/Tests/Unit/Queue/AzureStorageQueueTest.php @@ -10,6 +10,7 @@ use MicrosoftAzure\Storage\Queue\Internal\IQueue; use MicrosoftAzure\Storage\Queue\Models\CreateMessageResult; use MicrosoftAzure\Storage\Queue\Models\GetQueueMetadataResult; +use MicrosoftAzure\Storage\Queue\Models\ListMessagesOptions; use MicrosoftAzure\Storage\Queue\Models\ListMessagesResult; use MicrosoftAzure\Storage\Queue\Models\PeekMessagesOptions; use MicrosoftAzure\Storage\Queue\Models\PeekMessagesResult; @@ -945,6 +946,29 @@ protected function createMockQueueMessage(string $messageText, string $messageId return $queueMessage; } + /** + * @test + */ + public function dequeueSetsVisibilityTimeout(): void + { + $queue = $this->createQueue('test-queue', ['visibilityTimeout' => 120]); + + $listResult = $this->createMock(ListMessagesResult::class); + $listResult->method('getQueueMessages')->willReturn([]); + + $this->queueService->expects($this->once()) + ->method('listMessages') + ->with( + 'test-queue', + $this->callback(function (ListMessagesOptions $options) { + return $options->getVisibilityTimeoutInSeconds() === 120; + }) + ) + ->willReturn($listResult); + + $queue->waitAndReserve(0); + } + /** * Helper method to setup a reserved message in the queue's internal tracking */