From 7789fc95c7893a7ea9b74f72b1a8f5abf65ca9f0 Mon Sep 17 00:00:00 2001 From: Durable Workflow Date: Sat, 17 Oct 2026 19:58:04 +0000 Subject: [PATCH 1/4] Qualify published queue consumer on Workflow 2.5.31 --- .github/queue-contention/current/composer.json | 4 ++-- .github/queue-contention/current/composer.lock | 16 ++++++++-------- .github/workflows/published-queue.yml | 3 ++- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/.github/queue-contention/current/composer.json b/.github/queue-contention/current/composer.json index cfff13c8..9299ad5d 100644 --- a/.github/queue-contention/current/composer.json +++ b/.github/queue-contention/current/composer.json @@ -2,7 +2,7 @@ "name": "durable-workflow/current-queue-consumer", "require": { "php": "^8.3.6", - "durable-workflow/workflow": "2.5.27", + "durable-workflow/workflow": "2.5.31", "laravel/framework": "13.37.0", "orchestra/testbench": "11.3.0", "phpunit/phpunit": "12.5.40" @@ -12,6 +12,6 @@ "sort-packages": true }, "extra": { - "workflow-published-reference": "8ba5bec6f5fb72c6f159f4b82695f19b06017e63" + "workflow-published-reference": "3b5e58cfbec52783d28202ce860f7f83f8aad0ac" } } diff --git a/.github/queue-contention/current/composer.lock b/.github/queue-contention/current/composer.lock index 78152dae..7c4c5228 100644 --- a/.github/queue-contention/current/composer.lock +++ b/.github/queue-contention/current/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "69447ba9f2917c0958865895592dbe2d", + "content-hash": "6d2c9ddaa9a057c778f80e544046968a", "packages": [ { "name": "apache/avro", @@ -585,16 +585,16 @@ }, { "name": "durable-workflow/workflow", - "version": "2.5.27", + "version": "2.5.31", "source": { "type": "git", "url": "https://github.com/durable-workflow/workflow.git", - "reference": "8ba5bec6f5fb72c6f159f4b82695f19b06017e63" + "reference": "3b5e58cfbec52783d28202ce860f7f83f8aad0ac" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/durable-workflow/workflow/zipball/8ba5bec6f5fb72c6f159f4b82695f19b06017e63", - "reference": "8ba5bec6f5fb72c6f159f4b82695f19b06017e63", + "url": "https://api.github.com/repos/durable-workflow/workflow/zipball/3b5e58cfbec52783d28202ce860f7f83f8aad0ac", + "reference": "3b5e58cfbec52783d28202ce860f7f83f8aad0ac", "shasum": "" }, "require": { @@ -627,7 +627,7 @@ "dev-main": "2.0.x-dev" }, "durable-workflow": { - "product-train": "2.5.27", + "product-train": "2.5.31", "laravel-embedded-upgrade-contract": "resources/laravel-embedded-upgrade-contract.json", "laravel-dependency-security-policy": "resources/laravel-dependency-security-policy.json" } @@ -654,9 +654,9 @@ "description": "Embedded durable workflow runtime and orchestration engine for Laravel applications.", "support": { "issues": "https://github.com/durable-workflow/workflow/issues", - "source": "https://github.com/durable-workflow/workflow/tree/2.5.27" + "source": "https://github.com/durable-workflow/workflow/tree/2.5.31" }, - "time": "2026-10-16T14:24:11+00:00" + "time": "2026-10-17T19:27:38+00:00" }, { "name": "egulias/email-validator", diff --git a/.github/workflows/published-queue.yml b/.github/workflows/published-queue.yml index 85d91167..c65cf677 100644 --- a/.github/workflows/published-queue.yml +++ b/.github/workflows/published-queue.yml @@ -13,7 +13,8 @@ permissions: jobs: published-queue: - runs-on: ubuntu-latest + # Qualify the image's stock PHP 8.3 without a floating OS migration. + runs-on: ubuntu-24.04 timeout-minutes: 8 steps: - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 From 3183e8775f80e2671caa6e609df60a2a391f01f5 Mon Sep 17 00:00:00 2001 From: Durable Workflow Date: Sat, 17 Oct 2026 20:13:27 +0000 Subject: [PATCH 2/4] Capture repair state in a fresh failure-only consumer diagnostic --- .github/queue-contention/runner.php | 6 ++++++ .github/workflows/published-queue.yml | 12 ++++++++++++ 2 files changed, 18 insertions(+) diff --git a/.github/queue-contention/runner.php b/.github/queue-contention/runner.php index f05cba7c..da42aba3 100644 --- a/.github/queue-contention/runner.php +++ b/.github/queue-contention/runner.php @@ -321,9 +321,15 @@ protected function defineEnvironment($app): void 'stage' => 'before_update', 'pid' => getmypid(), 'task_id' => $task->id, + 'task_type' => $task->getRawOriginal('task_type'), 'status' => $task->status->value, + 'status_before' => $task->getRawOriginal('status'), 'repair_before' => $task->getOriginal('repair_count'), 'repair_after' => $task->repair_count, + 'last_dispatched_at' => $task->getRawOriginal('last_dispatched_at'), + 'available_at' => $task->getRawOriginal('available_at'), + 'lease_expires_at' => $task->getRawOriginal('lease_expires_at'), + 'delivery_reference' => $reference, 'native_row' => $row, 'observed_unix' => time(), ], JSON_THROW_ON_ERROR) . "\n", FILE_APPEND | LOCK_EX); diff --git a/.github/workflows/published-queue.yml b/.github/workflows/published-queue.yml index c65cf677..f4c299ee 100644 --- a/.github/workflows/published-queue.yml +++ b/.github/workflows/published-queue.yml @@ -47,6 +47,7 @@ jobs: php -r 'require ".github/queue-contention/current/vendor/autoload.php"; $manifest=json_decode(file_get_contents(".github/queue-contention/current/composer.json"), true, flags: JSON_THROW_ON_ERROR); if (Composer\InstalledVersions::getPrettyVersion("durable-workflow/workflow") !== $manifest["require"]["durable-workflow/workflow"] || Composer\InstalledVersions::getReference("durable-workflow/workflow") !== $manifest["extra"]["workflow-published-reference"]) { throw new RuntimeException("Installed package provenance differs."); }' - name: Execute the original continuous four-worker cohort + id: ordinary run: | sudo systemd-run --scope --quiet \ --property=CPUQuota=200% --property=MemoryMax=2G --property=MemorySwapMax=0 \ @@ -54,3 +55,14 @@ jobs: env XDEBUG_MODE=off DW_PROBE_QUEUE_WAKE=true DW_PROBE_CONTINUOUS=true \ DW_QUALIFICATION_AUTOLOAD="$PWD/.github/queue-contention/current/vendor/autoload.php" \ bash .github/queue-contention/current/limited-cohort.sh + + - name: Capture one fresh diagnostic original after a cohort failure + if: ${{ failure() && steps.ordinary.outcome == 'failure' }} + run: | + sudo systemd-run --scope --quiet \ + --property=CPUQuota=200% --property=MemoryMax=2G --property=MemorySwapMax=0 \ + runuser --user "$(id -un)" -- \ + env XDEBUG_MODE=off DW_PROBE_QUEUE_WAKE=true DW_PROBE_CONTINUOUS=true \ + DW_PROBE_REPAIR_OBSERVATIONS=true \ + DW_QUALIFICATION_AUTOLOAD="$PWD/.github/queue-contention/current/vendor/autoload.php" \ + bash .github/queue-contention/current/limited-cohort.sh From e3a04c22bfdf408350de379afbd53ba52f4e2ac4 Mon Sep 17 00:00:00 2001 From: Durable Workflow Date: Sat, 17 Oct 2026 21:13:04 +0000 Subject: [PATCH 3/4] test: select published 2.5.32 for the four-worker queue consumer --- .github/queue-contention/current/composer.json | 4 ++-- .github/queue-contention/current/composer.lock | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/queue-contention/current/composer.json b/.github/queue-contention/current/composer.json index 9299ad5d..87153897 100644 --- a/.github/queue-contention/current/composer.json +++ b/.github/queue-contention/current/composer.json @@ -2,7 +2,7 @@ "name": "durable-workflow/current-queue-consumer", "require": { "php": "^8.3.6", - "durable-workflow/workflow": "2.5.31", + "durable-workflow/workflow": "2.5.32", "laravel/framework": "13.37.0", "orchestra/testbench": "11.3.0", "phpunit/phpunit": "12.5.40" @@ -12,6 +12,6 @@ "sort-packages": true }, "extra": { - "workflow-published-reference": "3b5e58cfbec52783d28202ce860f7f83f8aad0ac" + "workflow-published-reference": "78075b6f7e513a93db7d613bdd09b9e777fbb58a" } } diff --git a/.github/queue-contention/current/composer.lock b/.github/queue-contention/current/composer.lock index 7c4c5228..20f85692 100644 --- a/.github/queue-contention/current/composer.lock +++ b/.github/queue-contention/current/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "6d2c9ddaa9a057c778f80e544046968a", + "content-hash": "2548ed476874c7738fb4f713b864a84b", "packages": [ { "name": "apache/avro", @@ -585,16 +585,16 @@ }, { "name": "durable-workflow/workflow", - "version": "2.5.31", + "version": "2.5.32", "source": { "type": "git", "url": "https://github.com/durable-workflow/workflow.git", - "reference": "3b5e58cfbec52783d28202ce860f7f83f8aad0ac" + "reference": "78075b6f7e513a93db7d613bdd09b9e777fbb58a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/durable-workflow/workflow/zipball/3b5e58cfbec52783d28202ce860f7f83f8aad0ac", - "reference": "3b5e58cfbec52783d28202ce860f7f83f8aad0ac", + "url": "https://api.github.com/repos/durable-workflow/workflow/zipball/78075b6f7e513a93db7d613bdd09b9e777fbb58a", + "reference": "78075b6f7e513a93db7d613bdd09b9e777fbb58a", "shasum": "" }, "require": { @@ -627,7 +627,7 @@ "dev-main": "2.0.x-dev" }, "durable-workflow": { - "product-train": "2.5.31", + "product-train": "2.5.32", "laravel-embedded-upgrade-contract": "resources/laravel-embedded-upgrade-contract.json", "laravel-dependency-security-policy": "resources/laravel-dependency-security-policy.json" } @@ -654,9 +654,9 @@ "description": "Embedded durable workflow runtime and orchestration engine for Laravel applications.", "support": { "issues": "https://github.com/durable-workflow/workflow/issues", - "source": "https://github.com/durable-workflow/workflow/tree/2.5.31" + "source": "https://github.com/durable-workflow/workflow/tree/2.5.32" }, - "time": "2026-10-17T19:27:38+00:00" + "time": "2026-10-17T20:57:32+00:00" }, { "name": "egulias/email-validator", From c903ee3142f4cba122f13c39c79bab99343dc4ba Mon Sep 17 00:00:00 2001 From: Durable Workflow Date: Sat, 17 Oct 2026 21:28:14 +0000 Subject: [PATCH 4/4] test: report typed native claim pressure and elapsed admission waits --- .github/queue-contention/runner.php | 37 +++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/.github/queue-contention/runner.php b/.github/queue-contention/runner.php index da42aba3..6846612d 100644 --- a/.github/queue-contention/runner.php +++ b/.github/queue-contention/runner.php @@ -304,6 +304,11 @@ protected function defineEnvironment($app): void 'rollback' => null, 'errors' => 0, 'repairs' => 0, + 'job_started_ns' => null, + 'job_pdo' => null, + 'claim_task_id' => null, + 'claim_started_ns' => null, + 'claim_admissions' => 0, ]; $deliveryErrorPath = $directory . '/delivery-errors.jsonl'; $repairObservationPath = $directory . '/repair-observations.jsonl'; @@ -337,6 +342,29 @@ protected function defineEnvironment($app): void } $app['events']->listen(Illuminate\Queue\Events\JobProcessing::class, static function () use ($diagnostics): void { $diagnostics->rollback = null; + $diagnostics->job_started_ns = hrtime(true); + $diagnostics->job_pdo = DB::connection('baseline')->getRawPdo(); + $diagnostics->claim_task_id = null; + $diagnostics->claim_started_ns = null; + $diagnostics->claim_admissions = 0; +}); +DB::connection('baseline')->beforeExecuting(static function (string $sql, array $bindings) use ($diagnostics): void { + if (! str_starts_with($sql, 'update "workflow_tasks" set "id" =') || ! isset($bindings[0])) { + return; + } + foreach (debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 24) as $frame) { + if (($frame['class'] ?? null) !== Workflow\V2\Support\ActivityTaskClaimer::class + || ($frame['function'] ?? null) !== 'claimDetailed') { + continue; + } + if ($diagnostics->claim_task_id !== $bindings[0]) { + $diagnostics->claim_task_id = $bindings[0]; + $diagnostics->claim_started_ns = hrtime(true); + $diagnostics->claim_admissions = 0; + } + $diagnostics->claim_admissions++; + return; + } }); $app['events']->listen(Illuminate\Database\Events\TransactionRolledBack::class, static function ($event) use ( $diagnostics @@ -345,6 +373,7 @@ protected function defineEnvironment($app): void $diagnostics->rollback = [ 'level' => $event->connection->transactionLevel(), 'pdo_in_transaction' => $pdo instanceof PDO ? $pdo->inTransaction() : null, + 'same_pdo_as_job' => $pdo instanceof PDO && $pdo === $diagnostics->job_pdo, ]; }); $app['events']->listen(Illuminate\Queue\Events\JobExceptionOccurred::class, static function ($event) use ( @@ -361,6 +390,14 @@ protected function defineEnvironment($app): void 'queue_job' => $event->job->getJobId(), 'task_id' => transportTaskId($event->job->payload()), 'summary' => substr($event->exception->getMessage(), 0, 384), + 'exception_class' => $event->exception::class, + 'native_error_info' => $event->exception instanceof PDOException ? $event->exception->errorInfo : null, + 'job_elapsed_ms' => $diagnostics->job_started_ns === null ? null + : round((hrtime(true) - $diagnostics->job_started_ns) / 1_000_000, 3), + 'claim_task_id' => $diagnostics->claim_task_id, + 'claim_admissions' => $diagnostics->claim_admissions, + 'claim_elapsed_ms' => $diagnostics->claim_started_ns === null ? null + : round((hrtime(true) - $diagnostics->claim_started_ns) / 1_000_000, 3), 'frames' => array_slice(array_values($frames), 0, 8), 'last_rollback' => $diagnostics->rollback, ], JSON_THROW_ON_ERROR) . "\n", FILE_APPEND | LOCK_EX);