Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
94 commits
Select commit Hold shift + click to select a range
b07164e
Give codec work under the transition lock its own permit
durable-workflow-ops Oct 20, 2026
095bf3e
Reproduce native empty and malformed command declaration boundaries
durable-workflow-ops Oct 15, 2026
1a739d4
Preserve explicit worker command declaration snapshots
durable-workflow-ops Oct 15, 2026
c4e37fd
Report leased and empty poll statuses like the worker protocol
durable-workflow-ops Oct 20, 2026
d5d880f
Let held long polls wait without the transition lock
durable-workflow-ops Oct 20, 2026
7e49193
Import the codec test names explicitly
durable-workflow-ops Oct 20, 2026
0ac1b8f
Retry the PHP reference's lock-pressure refusals below the SDK transport
durable-workflow-ops Oct 20, 2026
e737397
Design the backup-first native takeover
durable-workflow-ops Oct 20, 2026
eb8604a
Require a fenced PHP release before takeover
durable-workflow-ops Oct 20, 2026
98ef1af
Back off a held poll's timed reads up to 250 ms
durable-workflow-ops Oct 20, 2026
5ef7f1e
Merge remote-tracking branch 'origin/main' into rust-325-transition-c…
durable-workflow-ops Oct 20, 2026
1a00066
Merge remote-tracking branch 'origin/main' into rust-325-worker-contr…
durable-workflow-ops Oct 20, 2026
726427f
Merge remote-tracking branch 'origin/main' into rust-325-poll-status
durable-workflow-ops Oct 20, 2026
17ec64f
Merge remote-tracking branch 'origin/main' into rust-325-takeover-design
durable-workflow-ops Oct 20, 2026
758fd37
Merge remote-tracking branch 'origin/main' into rust-325-probe-lock-p…
durable-workflow-ops Oct 20, 2026
1572827
Merge remote-tracking branch 'origin/main' into rust-325-lock-free-wa…
durable-workflow-ops Oct 20, 2026
eb27267
Keep the readiness reads beside the claims they mirror
durable-workflow-ops Oct 20, 2026
00b8b65
Record that native's schema must first converge on the source release
durable-workflow-ops Oct 20, 2026
026e258
Reproduce default and opt-out workflow definition upgrade stalls
durable-workflow-ops Oct 20, 2026
e03bd5f
Allow strict replay by replacement workflow definitions and explain r…
durable-workflow-ops Oct 20, 2026
cd7d110
Convert each PHP release layout to native's instead of chasing it
durable-workflow-ops Oct 20, 2026
57de9ec
Bind routing diagnostics to the canonical selected or current run
durable-workflow-ops Oct 20, 2026
a8e324a
Exercise configured PostgreSQL bound queries through transaction poolers
durable-workflow-ops Oct 20, 2026
0447dd5
Reproduce readiness passing a connected database with broken bound reads
durable-workflow-ops Oct 20, 2026
ba06b0f
Use native unnamed PostgreSQL binding and probe primary query readiness
durable-workflow-ops Oct 20, 2026
2e59f1b
Qualify PostgreSQL transaction pools in ordinary PHP CI
durable-workflow-ops Oct 20, 2026
75d6f38
Clarify replay routing decisions and preserve explicit metrics clearing
durable-workflow-ops Oct 20, 2026
e692df2
Merge remote-tracking branch 'origin/main' into fix/worker-definition…
durable-workflow-ops Oct 20, 2026
9ec7444
Merge remote-tracking branch 'origin/main' into rust-325-probe-lock-p…
durable-workflow-ops Oct 20, 2026
d867e0f
Print failed Rust tests in the failing step's own log
durable-workflow-ops Oct 20, 2026
c78780a
Merge remote-tracking branch 'origin/main' into rust-325-takeover-design
durable-workflow-ops Oct 20, 2026
bac6c80
Describe queue delivery references as the lookup metadata they are
durable-workflow-ops Oct 20, 2026
c14032c
Take over a stopped PHP PostgreSQL database backup-first
durable-workflow-ops Oct 20, 2026
6cc5d3d
Match the design to the SQLite and PostgreSQL takeovers as built
durable-workflow-ops Oct 20, 2026
d94b118
Call the Rust test failure summary through a named trap function
durable-workflow-ops Oct 20, 2026
295038c
Merge branch 'main' into rust-325-poll-status
rmcdaniel Oct 20, 2026
1e65412
Merge remote-tracking branch 'origin/rust-325-poll-status' into rust-…
durable-workflow-ops Oct 20, 2026
5084d24
Merge pull request #509 from durable-workflow/rust-325-poll-status
rmcdaniel Oct 20, 2026
3a46764
Merge branch 'main' into rust-325-lock-free-waiting
rmcdaniel Oct 20, 2026
e6e349c
fix: restore readiness probe fixture transaction ownership
durable-workflow-ops Oct 20, 2026
4e83744
Merge remote-tracking branch 'origin/main' into fix/pgsql-pooler-read…
durable-workflow-ops Oct 20, 2026
3c1cc66
Take over a stopped PHP MySQL or MariaDB database in recorded steps
durable-workflow-ops Oct 20, 2026
fe2b26e
Retry lock-pressure refusals inside the probes' recorders
durable-workflow-ops Oct 20, 2026
29e798d
Merge remote-tracking branch 'origin/rust-325-sqlite-takeover' into r…
durable-workflow-ops Oct 20, 2026
b868247
Merge remote-tracking branch 'origin/rust-325-postgres-takeover' into…
durable-workflow-ops Oct 20, 2026
7fec435
Merge remote-tracking branch 'origin/main' into rust-325-transition-c…
durable-workflow-ops Oct 20, 2026
b9d5368
Merge remote-tracking branch 'origin/main' into rust-325-worker-contr…
durable-workflow-ops Oct 20, 2026
48ced5b
Accept MariaDB's backend name in the cohort's takeover check
durable-workflow-ops Oct 20, 2026
1800199
Merge pull request #531 from durable-workflow/fix/pgsql-pooler-readin…
rmcdaniel Oct 20, 2026
5826c17
Merge branch 'rust-325-postgres-takeover' into rust-325-mysql-takeover
durable-workflow-ops Oct 20, 2026
e4ec512
Merge remote-tracking branch 'origin/rust-325-sqlite-takeover' into r…
durable-workflow-ops Oct 20, 2026
4d8a28b
chore: prepare Server 2.9.8 pooler compatibility release
durable-workflow-ops Oct 20, 2026
132755a
Prepare a PHP SQLite source in WAL mode for the upgrade commands
durable-workflow-ops Oct 20, 2026
2c1ee85
Merge branch 'main' into rust-325-transition-codec
rmcdaniel Oct 20, 2026
548e0e0
Merge branch 'main' into rust-325-worker-contracts
rmcdaniel Oct 20, 2026
924e45f
Describe the MySQL journal and the SQLite WAL preparation as built
durable-workflow-ops Oct 20, 2026
9145386
Merge branch 'main' into rust-325-takeover-design
rmcdaniel Oct 20, 2026
4d9264a
Merge branch 'main' into rust-325-lock-free-waiting
rmcdaniel Oct 20, 2026
3adc901
Merge pull request #508 from durable-workflow/rust-325-worker-contracts
rmcdaniel Oct 20, 2026
1df8cbe
Merge remote-tracking branch 'origin/main' into rust-325-lock-free-wa…
durable-workflow-ops Oct 20, 2026
09d1742
Merge remote-tracking branch 'origin/main' into rust-325-transition-c…
durable-workflow-ops Oct 20, 2026
3f0a838
Merge remote-tracking branch 'origin/main' into release/server-2.9.8-524
durable-workflow-ops Oct 20, 2026
8957ba2
Merge pull request #516 from durable-workflow/rust-325-lock-free-waiting
rmcdaniel Oct 20, 2026
32256cb
Merge remote-tracking branch 'origin/main' into release/server-2.9.8-524
durable-workflow-ops Oct 20, 2026
3f1c709
Merge remote-tracking branch 'origin/main' into rust-325-transition-c…
durable-workflow-ops Oct 20, 2026
361a96b
Merge pull request #537 from durable-workflow/release/server-2.9.8-524
rmcdaniel Oct 20, 2026
a25fa49
Keep the activity deadline probe's own poll retry accounting
durable-workflow-ops Oct 20, 2026
0e5843b
Merge remote-tracking branch 'origin/main' into rust-325-probe-lock-p…
durable-workflow-ops Oct 20, 2026
d3c3c34
Let SQLite source preparation wait briefly for a closing writer
durable-workflow-ops Oct 20, 2026
e75c95e
Merge branch 'main' into rust-325-transition-codec
rmcdaniel Oct 20, 2026
fa7695f
Resume a PHP-accepted signal after takeover and refuse unsupported fe…
durable-workflow-ops Oct 20, 2026
ee88ac6
Merge pull request #507 from durable-workflow/rust-325-transition-codec
rmcdaniel Oct 20, 2026
ac7d24a
Merge branch 'main' into rust-325-takeover-design
rmcdaniel Oct 20, 2026
83f4d6b
Merge pull request #517 from durable-workflow/rust-325-takeover-design
rmcdaniel Oct 20, 2026
6978d60
Redeliver a PHP lease that expires after the takeover
durable-workflow-ops Oct 20, 2026
9467878
Merge remote-tracking branch 'origin/main' into fix/worker-definition…
durable-workflow-ops Oct 20, 2026
ebfcbff
Fence entry-schema failures and require safe replacement workers
durable-workflow-ops Oct 20, 2026
85a81e6
Keep replacement safety decision in one final return
durable-workflow-ops Oct 20, 2026
a44c739
Merge remote-tracking branch 'origin/main' into rust-325-probe-lock-p…
durable-workflow-ops Oct 20, 2026
64c6968
Merge pull request #525 from durable-workflow/fix/worker-definition-e…
rmcdaniel Oct 20, 2026
3a07c55
Prepare Server 2.9.9 entry-safety release
durable-workflow-ops Oct 20, 2026
f94e33e
Merge remote-tracking branch 'origin/main' into rust-325-probe-lock-p…
durable-workflow-ops Oct 20, 2026
f4f78d0
Record two repeated matched PHP/native pairs after #516
durable-workflow-ops Oct 20, 2026
2d5fbcc
Merge pull request #515 from durable-workflow/rust-325-probe-lock-pre…
rmcdaniel Oct 20, 2026
3dab83e
Merge remote-tracking branch 'origin/main' into rust-325-upgrade-signal
durable-workflow-ops Oct 20, 2026
b67864d
Merge branch 'main' into release/server-2.9.9-entry-safety
rmcdaniel Oct 20, 2026
6a3c67f
Merge pull request #541 from durable-workflow/release/server-2.9.9-en…
rmcdaniel Oct 20, 2026
5712431
Merge branch 'main' into rust-325-repeated-matched
rmcdaniel Oct 20, 2026
ef72830
Merge pull request #542 from durable-workflow/rust-325-repeated-matched
rmcdaniel Oct 20, 2026
70f610b
Compare restart history without the public principal; scope the SQLit…
durable-workflow-ops Oct 20, 2026
ffeccc9
Merge remote-tracking branch 'origin/main' into rust-325-upgrade-signal
durable-workflow-ops Oct 20, 2026
7670598
Merge pull request #539 from durable-workflow/rust-325-upgrade-signal
rmcdaniel Oct 20, 2026
3692b6d
Merge pull request #538 from durable-workflow/rust-325-sqlite-wal-source
rmcdaniel Oct 20, 2026
93319a7
Merge pull request #536 from durable-workflow/rust-325-mysql-takeover
rmcdaniel Oct 20, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions .github/workflows/phpunit-feature.yml
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,21 @@ jobs:
done
[ "$health" = healthy ]
done
for mode in session transaction0 transaction200; do
pool_mode=transaction
prepared_statements=0
[ "$mode" != session ] || pool_mode=session
[ "$mode" != transaction200 ] || prepared_statements=200
docker run --detach \
--name "dw-server-pooler-${{ github.run_id }}-${{ github.run_attempt }}-${{ github.job }}-$mode" \
--network "dw-server-feature-${{ github.run_id }}-${{ github.run_attempt }}-${{ github.job }}" \
--memory 128m --memory-swap 128m \
-e DB_HOST="dw-server-backup-pgsql-${{ github.run_id }}-${{ github.run_attempt }}-${{ github.job }}" \
-e DB_NAME=postgres -e DB_USER=postgres -e DB_PASSWORD=pooler-disposable-password \
-e AUTH_TYPE=trust -e "POOL_MODE=$pool_mode" -e "MAX_PREPARED_STATEMENTS=$prepared_statements" \
-e DEFAULT_POOL_SIZE=2 -e MIN_POOL_SIZE=2 -e SERVER_ROUND_ROBIN=1 \
edoburu/pgbouncer@sha256:b17551c776ef7e5769ef80b956d20f85e2fd25dd8912d31d58f782aad495b711
done
tar \
--exclude=vendor \
--exclude='*/vendor' \
Expand All @@ -236,6 +251,9 @@ jobs:
-e DW_TEST_COMPLETION_MYSQL_HOST="dw-server-backup-mysql-${{ github.run_id }}-${{ github.run_attempt }}-${{ github.job }}" \
-e DW_TEST_BACKUP_PGSQL_HOST="dw-server-backup-pgsql-${{ github.run_id }}-${{ github.run_attempt }}-${{ github.job }}" \
-e DW_TEST_COMPLETION_PGSQL_HOST="dw-server-backup-pgsql-${{ github.run_id }}-${{ github.run_attempt }}-${{ github.job }}" \
-e DW_POOLER_TEST_HOST="dw-server-backup-pgsql-${{ github.run_id }}-${{ github.run_attempt }}-${{ github.job }}" \
-e DW_POOLER_TEST_PORT=5432 -e DW_POOLER_TEST_DATABASE=postgres -e DW_POOLER_TEST_USER=postgres \
-e DW_POOLER_TEST_PREFIX="dw-server-pooler-${{ github.run_id }}-${{ github.run_attempt }}-${{ github.job }}" \
-w /app \
--entrypoint sh \
durable-workflow-server-corpus-validator \
Expand Down Expand Up @@ -283,6 +301,9 @@ jobs:
- name: Clean up test services
if: always()
run: |
for mode in session transaction0 transaction200; do
docker rm -f "dw-server-pooler-${{ github.run_id }}-${{ github.run_attempt }}-${{ github.job }}-$mode" >/dev/null 2>&1 || true
done
docker rm -f \
"dw-server-s3-${{ github.run_id }}-${{ github.run_attempt }}-${{ github.job }}" \
"dw-server-backup-mysql-${{ github.run_id }}-${{ github.run_attempt }}-${{ github.job }}" \
Expand Down
29 changes: 23 additions & 6 deletions .github/workflows/server-parity.yml
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,11 @@ jobs:
- name: Bootstrap independent published PHP and native MySQL databases
run: |
set -euo pipefail
# Failed Rust tests are printed from their evidence files into this step's log.
rust_test_failures() {
bash scripts/conformance/server-parity/rust-test-failures.sh
}
trap rust_test_failures ERR
mkdir -p cargo-home rust-target parity-evidence mysql-state
chmod 0777 parity-evidence
docker network create "$RESOURCE_SCOPE"
Expand Down Expand Up @@ -663,14 +668,14 @@ jobs:
cmp parity-evidence/catalog-before.json parity-evidence/catalog-after.json
- name: Compare separate configured role-token cohort
run: bash scripts/conformance/server-parity/role-profile.sh mysql
- name: Inspect separate published PHP upgrade source without takeover
- name: Back up, take over and resume a separate published PHP upgrade source
timeout-minutes: 8
run: bash scripts/conformance/server-parity/upgrade-source-profile.sh mysql
- name: Retire upgrade source cohort
if: always()
timeout-minutes: 3
run: bash scripts/conformance/server-parity/upgrade-source-cleanup.sh mysql
- name: Inspect published PHP 2.9.7 upgrade source without takeover
- name: Back up, take over and resume a published PHP 2.9.7 upgrade source
timeout-minutes: 8
env:
DW_PARITY_UPGRADE_LABEL: php297
Expand Down Expand Up @@ -871,6 +876,11 @@ jobs:
POSTGRES_IMAGE: ${{ matrix.image }}
run: |
set -euo pipefail
# Failed Rust tests are printed from their evidence files into this step's log.
rust_test_failures() {
bash scripts/conformance/server-parity/rust-test-failures.sh
}
trap rust_test_failures ERR
mkdir -p cargo-home rust-target parity-evidence pg-state
chmod 0777 parity-evidence
docker network create "$RESOURCE_SCOPE"
Expand Down Expand Up @@ -1157,14 +1167,14 @@ jobs:
env:
POSTGRES_IMAGE: ${{ matrix.image }}
run: bash scripts/conformance/server-parity/role-profile.sh pgsql
- name: Inspect separate published PHP upgrade source without takeover
- name: Back up, take over and resume a separate published PHP upgrade source
timeout-minutes: 8
run: bash scripts/conformance/server-parity/upgrade-source-profile.sh pgsql
- name: Retire upgrade source cohort
if: always()
timeout-minutes: 3
run: bash scripts/conformance/server-parity/upgrade-source-cleanup.sh pgsql
- name: Inspect published PHP 2.9.7 upgrade source without takeover
- name: Back up, take over and resume a published PHP 2.9.7 upgrade source
timeout-minutes: 8
env:
DW_PARITY_UPGRADE_LABEL: php297
Expand Down Expand Up @@ -1394,6 +1404,11 @@ jobs:
- name: Execute official Rust codec and cross-decode with published PHP
run: |
set -euo pipefail
# Failed Rust tests are printed from their evidence files into this step's log.
rust_test_failures() {
bash scripts/conformance/server-parity/rust-test-failures.sh
}
trap rust_test_failures ERR
mkdir -p cargo-home rust-target parity-evidence
# Compiling the library tests peaks near 2.5 GB; a 2 GB limit OOM-killed rustc (exit 101).
docker run --rm --user="$(id -u):$(id -g)" --cpus=2 --memory=4g --memory-swap=4g \
Expand Down Expand Up @@ -1642,7 +1657,7 @@ jobs:
env:
RESOURCE_SCOPE: dw-parity-${{ github.run_id }}-${{ github.run_attempt }}-${{ github.job }}
run: bash scripts/conformance/server-parity/role-profile.sh sqlite
- name: Inspect separate published PHP upgrade source without takeover
- name: Back up, take over and resume a separate published PHP upgrade source
timeout-minutes: 8
env:
RESOURCE_SCOPE: dw-parity-${{ github.run_id }}-${{ github.run_attempt }}-${{ github.job }}
Expand All @@ -1653,9 +1668,10 @@ jobs:
env:
RESOURCE_SCOPE: dw-parity-${{ github.run_id }}-${{ github.run_attempt }}-${{ github.job }}
run: bash scripts/conformance/server-parity/upgrade-source-cleanup.sh sqlite
- name: Inspect published PHP 2.9.7 upgrade source without takeover
- name: Back up, take over and resume a published PHP 2.9.7 upgrade source
timeout-minutes: 8
env:
RESOURCE_SCOPE: dw-parity-${{ github.run_id }}-${{ github.run_attempt }}-${{ github.job }}
DW_PARITY_UPGRADE_LABEL: php297
DW_PARITY_UPGRADE_EXPECTED_LAYOUT: php-2.9.7
DW_PARITY_UPGRADE_PHP_IMAGE: ghcr.io/durable-workflow/server@sha256:30c34c5f3256a812fbccbe505a068309b58b0c14d01ffff0465d88604cb36d50
Expand All @@ -1664,6 +1680,7 @@ jobs:
if: always()
timeout-minutes: 3
env:
RESOURCE_SCOPE: dw-parity-${{ github.run_id }}-${{ github.run_attempt }}-${{ github.job }}
DW_PARITY_UPGRADE_LABEL: php297
DW_PARITY_UPGRADE_EXPECTED_LAYOUT: php-2.9.7
DW_PARITY_UPGRADE_PHP_IMAGE: ghcr.io/durable-workflow/server@sha256:30c34c5f3256a812fbccbe505a068309b58b0c14d01ffff0465d88604cb36d50
Expand Down
38 changes: 25 additions & 13 deletions app/Http/Controllers/Api/TaskQueueController.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use App\Support\TaskQueueAdmission;
use App\Support\TaskQueueBuildIdRolloutSnapshot;
use App\Support\TaskQueuePriorityFairnessSurface;
use App\Support\WorkflowDefinitionRouting;
use App\Support\WorkflowQueryTaskBroker;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
Expand All @@ -28,6 +29,7 @@ public function __construct(
private readonly TaskQueueBuildIdRolloutSnapshot $buildIdRollouts,
private readonly TaskQueuePriorityFairnessSurface $priorityFairness,
private readonly DeploymentLifecycleService $deployments,
private readonly WorkflowDefinitionRouting $definitionRouting,
) {}

public function index(Request $request): JsonResponse
Expand Down Expand Up @@ -67,22 +69,26 @@ public function show(Request $request, string $taskQueue): JsonResponse

$namespace = (string) $request->attributes->get('namespace');

return ControlPlaneProtocol::json(
$this->withAdmission(
$payload = $this->withAdmission(
$namespace,
$this->withRecentTaskFlow(
$namespace,
$this->withRecentTaskFlow(
$taskQueue,
StandaloneWorkerVisibility::queueDetail(
$namespace,
$taskQueue,
StandaloneWorkerVisibility::queueDetail(
$namespace,
$taskQueue,
WorkerRegistration::class,
now(),
$this->workerStaleAfterSeconds(),
)->toArray(),
),
WorkerRegistration::class,
now(),
$this->workerStaleAfterSeconds(),
)->toArray(),
),
);
$payload['definition_routing'] = $this->definitionRouting->forQueue($namespace, $taskQueue);
if ($payload['definition_routing']['blocked_sample_count'] > 0) {
$payload['repair']['needs_attention'] = true;
}

return ControlPlaneProtocol::json($payload);
}

/**
Expand Down Expand Up @@ -263,7 +269,7 @@ private function setBuildIdDrainIntent(Request $request, string $taskQueue, stri
}

/**
* @param array<string, mixed> $deployment
* @param array<string, mixed> $deployment
* @return array<string, mixed>
*/
private function buildIdLifecyclePayload(
Expand Down Expand Up @@ -351,7 +357,7 @@ private function normalizeDeploymentLifecycleTimestamps(array $deployment): arra
}

/**
* @param list<array<string, mixed>> $blockages
* @param list<array<string, mixed>> $blockages
*/
private function orderBlockages(array &$blockages): void
{
Expand Down Expand Up @@ -630,6 +636,7 @@ private function activityAttemptStateCounts(string $namespace, string $taskQueue
if ($attemptStatus === ActivityAttemptStatus::Running->value) {
$counts['running_count'] += $count;
$counts['open_count'] += $count;

continue;
}

Expand All @@ -639,13 +646,15 @@ private function activityAttemptStateCounts(string $namespace, string $taskQueue
) {
$counts['retrying_count'] += $count;
$counts['open_count'] += $count;

continue;
}

if ($attemptStatus === ActivityAttemptStatus::Expired->value) {
$counts['timed_out_count'] += $count;
$counts['expired_count'] += $count;
$counts['terminal_count'] += $count;

continue;
}

Expand All @@ -656,18 +665,21 @@ private function activityAttemptStateCounts(string $namespace, string $taskQueue
) {
$counts['timed_out_count'] += $count;
$counts['terminal_count'] += $count;

continue;
}

if ($attemptStatus === ActivityAttemptStatus::Failed->value) {
$counts['failed_count'] += $count;
$counts['terminal_count'] += $count;

continue;
}

if ($attemptStatus === ActivityAttemptStatus::Completed->value) {
$counts['completed_count'] += $count;
$counts['terminal_count'] += $count;

continue;
}

Expand Down
11 changes: 10 additions & 1 deletion app/Http/Controllers/Api/WorkerController.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
use App\Support\WorkflowHistoryPageToken;
use App\Support\WorkflowMetadataCapabilityPolicy;
use App\Support\WorkflowQueryTaskBroker;
use App\Support\WorkflowReplayEligibility;
use App\Support\WorkflowStreamCommandProcessor;
use App\Support\WorkflowStreamService;
use App\Support\WorkflowTaskLeaseRecovery;
Expand Down Expand Up @@ -160,6 +161,7 @@ class WorkerController
'version_marker_kind_mismatch',
'version_marker_sequence_invalid',
'version_range_invalid',
'workflow_entry_arguments_mismatch',
'workflow_nondeterministic',
];

Expand Down Expand Up @@ -407,7 +409,10 @@ public function register(Request $request): JsonResponse
$this->validateWorkerTaskCapacity($maxWorkflowTasks, $maxActivityTasks);
$maxWorkerSessions = $validated['max_concurrent_worker_sessions'] ?? 10;
$taskSlots = is_array($validated['task_slots'] ?? null) ? $validated['task_slots'] : [];
$processMetrics = $this->normalizeProcessMetrics($validated['process_metrics'] ?? null);
$processMetrics = [
...($this->normalizeProcessMetrics($validated['process_metrics'] ?? null) ?? []),
WorkflowReplayEligibility::PROTOCOL_METRIC => WorkerProtocol::requestVersion($request),
];
$releaseLeasesForRegistration = $this->shouldReleaseLeasesForWorkerRegistration($existing, $processMetrics);

try {
Expand Down Expand Up @@ -935,6 +940,10 @@ public function heartbeat(Request $request): JsonResponse
if (array_key_exists('process_metrics', $validated)) {
$update['process_metrics'] = $this->normalizeProcessMetrics($validated['process_metrics']);
}
$update['process_metrics'] = [
...(array_key_exists('process_metrics', $update) ? ($update['process_metrics'] ?? []) : ($worker->process_metrics ?? [])),
WorkflowReplayEligibility::PROTOCOL_METRIC => WorkerProtocol::requestVersion($request),
];

if (array_key_exists('heartbeat_interval_seconds', $validated)
&& $validated['heartbeat_interval_seconds'] !== null) {
Expand Down
1 change: 1 addition & 0 deletions app/Http/Controllers/Api/WorkflowController.php
Original file line number Diff line number Diff line change
Expand Up @@ -1250,6 +1250,7 @@ private function formatRun(WorkflowRun $run, string $namespace, array $descripti
'compatibility_supported_in_fleet' => $this->compatibilitySupportedInFleet($namespace, $run),
'compatibility_fleet_reason' => $this->compatibilityFleetReason($namespace, $run),
'payload_codec' => $run->payload_codec,
'definition_routing' => $description['definition_routing'] ?? null,
'execution_timeout_seconds' => $description['execution_timeout_seconds'] ?? null,
'run_timeout_seconds' => $runDescription['run_timeout_seconds'] ?? null,
'execution_deadline_at' => $runDescription['execution_deadline_at'] ?? null,
Expand Down
28 changes: 22 additions & 6 deletions app/Support/ServerReadiness.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public function snapshot(): array
: $this->cacheCheck();

$checks = [
'database' => $this->databaseCheck(),
'database' => $this->databaseCheck(probeQuery: true),
'migrations' => $this->migrationCheck(),
'queue' => $queue,
'default_namespace' => $this->defaultNamespaceCheck(),
Expand Down Expand Up @@ -93,22 +93,38 @@ public function bootstrapStatus(): array
]));
}

private function databaseCheck(): array
private function databaseCheck(bool $probeQuery = false): array
{
$queryAttempted = false;
try {
DB::connection()->getPdo();
$connection = DB::connection();
$connection->getPdo();
if ($probeQuery) {
$queryAttempted = true;
$row = $connection->selectOne('SELECT ? AS readiness_probe', [1], useReadPdo: false);
if ((string) ($row->readiness_probe ?? '') !== '1') {
throw new \UnexpectedValueException('The database did not return the readiness probe value.');
}
}

return [
'status' => 'ok',
'check_scope' => 'connection_only',
'check_scope' => $probeQuery ? 'bound_read_query' : 'connection_only',
'write_capacity_verified' => false,
'message' => 'The database connection is available. Write capacity has not been verified.',
'message' => $probeQuery
? 'The primary database connection can execute a bound read query. Write capacity has not been verified.'
: 'The database connection is available. Write capacity has not been verified.',
];
} catch (\Throwable $exception) {
$reason = $queryAttempted ? 'database_query_failed' : null;
if (BackendUnavailable::is($exception)) {
$reason = 'backend_unavailable';
}

return [
'status' => 'unavailable',
'message' => $exception->getMessage(),
'reason' => BackendUnavailable::is($exception) ? 'backend_unavailable' : null,
'reason' => $reason,
];
}
}
Expand Down
Loading
Loading