Skip to content

Commit d042ea9

Browse files
Queue::fake the seven V2 timer-wait cancel/terminate tests + respect available_at in drainReadyTasks
Same bucket A root cause as the signal-command fix: cancel/terminate tests that wait for a workflow to park on a timer were racing the real testbench queue workers. Under CI load the first waitFor could outrun the worker even with the 30s budget. Converting to Queue::fake + drainReadyTasks wasn't enough on its own because drainReadyTasks in V2WorkflowTest didn't consult `available_at` — a timer task scheduled for +2s was created with status=Ready, so the drain loop fired the timer immediately and the workflow completed before the test could cancel. Fix the drain filter so it matches the real worker's semantics: only run tasks whose `available_at` is null or already in the past. With the drain respecting `available_at`, these seven tests can now use the same Queue::fake + drainReadyTasks pattern as every other reliable test in the file: * testWorkflowCanBeCancelledWhileWaitingOnTimer * testWorkflowCanBeTerminatedWhileWaitingOnTimer * testCancelWithoutReasonLeavesReasonNull * testCancelCreatesFailureRowWithCancelledCategory * testTerminateCreatesFailureRowWithTerminatedCategory * testCancelWithoutReasonCreatesFailureRowWithDefaultMessage * testCancelFailureRowAppearsInFailureSnapshots Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent a349bbe commit d042ea9

1 file changed

Lines changed: 32 additions & 0 deletions

File tree

tests/Feature/V2/V2WorkflowTest.php

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6561,13 +6561,17 @@ public function testWorkflowCanCompleteImmediateTimerWithoutSchedulingATimerTask
65616561

65626562
public function testWorkflowCanBeCancelledWhileWaitingOnTimer(): void
65636563
{
6564+
Queue::fake();
6565+
65646566
$workflow = WorkflowStub::make(TestTimerWorkflow::class);
65656567
$workflow->start(2);
65666568

65676569
$runId = $workflow->runId();
65686570

65696571
$this->assertNotNull($runId);
65706572

6573+
$this->drainReadyTasks();
6574+
65716575
$this->waitFor(static fn (): bool => $workflow->refresh()->status() === 'waiting'
65726576
&& $workflow->summary()?->wait_kind === 'timer');
65736577

@@ -6680,13 +6684,17 @@ public function testRunTargetedCancelUsesRunScopeForCurrentRun(): void
66806684

66816685
public function testWorkflowCanBeTerminatedWhileWaitingOnTimer(): void
66826686
{
6687+
Queue::fake();
6688+
66836689
$workflow = WorkflowStub::make(TestTimerWorkflow::class);
66846690
$workflow->start(5);
66856691

66866692
$runId = $workflow->runId();
66876693

66886694
$this->assertNotNull($runId);
66896695

6696+
$this->drainReadyTasks();
6697+
66906698
$this->waitFor(static fn (): bool => $workflow->refresh()->status() === 'waiting'
66916699
&& $workflow->summary()?->wait_kind === 'timer');
66926700

@@ -7803,13 +7811,17 @@ public function testWorkflowCanBeTerminatedWithReasonWhileWaitingOnActivity(): v
78037811

78047812
public function testCancelWithoutReasonLeavesReasonNull(): void
78057813
{
7814+
Queue::fake();
7815+
78067816
$workflow = WorkflowStub::make(TestTimerWorkflow::class, 'cancel-no-reason');
78077817
$workflow->start(2);
78087818

78097819
$runId = $workflow->runId();
78107820

78117821
$this->assertNotNull($runId);
78127822

7823+
$this->drainReadyTasks();
7824+
78137825
$this->waitFor(static fn (): bool => $workflow->refresh()->status() === 'waiting'
78147826
&& $workflow->summary()?->wait_kind === 'timer');
78157827

@@ -7833,13 +7845,17 @@ public function testCancelWithoutReasonLeavesReasonNull(): void
78337845

78347846
public function testCancelCreatesFailureRowWithCancelledCategory(): void
78357847
{
7848+
Queue::fake();
7849+
78367850
$workflow = WorkflowStub::make(TestTimerWorkflow::class, 'cancel-failure-row');
78377851
$workflow->start(5);
78387852

78397853
$runId = $workflow->runId();
78407854

78417855
$this->assertNotNull($runId);
78427856

7857+
$this->drainReadyTasks();
7858+
78437859
$this->waitFor(static fn (): bool => $workflow->refresh()->status() === 'waiting'
78447860
&& $workflow->summary()?->wait_kind === 'timer');
78457861

@@ -7883,13 +7899,17 @@ public function testCancelCreatesFailureRowWithCancelledCategory(): void
78837899

78847900
public function testTerminateCreatesFailureRowWithTerminatedCategory(): void
78857901
{
7902+
Queue::fake();
7903+
78867904
$workflow = WorkflowStub::make(TestTimerWorkflow::class, 'terminate-failure-row');
78877905
$workflow->start(5);
78887906

78897907
$runId = $workflow->runId();
78907908

78917909
$this->assertNotNull($runId);
78927910

7911+
$this->drainReadyTasks();
7912+
78937913
$this->waitFor(static fn (): bool => $workflow->refresh()->status() === 'waiting'
78947914
&& $workflow->summary()?->wait_kind === 'timer');
78957915

@@ -7933,13 +7953,17 @@ public function testTerminateCreatesFailureRowWithTerminatedCategory(): void
79337953

79347954
public function testCancelWithoutReasonCreatesFailureRowWithDefaultMessage(): void
79357955
{
7956+
Queue::fake();
7957+
79367958
$workflow = WorkflowStub::make(TestTimerWorkflow::class, 'cancel-no-reason-failure');
79377959
$workflow->start(5);
79387960

79397961
$runId = $workflow->runId();
79407962

79417963
$this->assertNotNull($runId);
79427964

7965+
$this->drainReadyTasks();
7966+
79437967
$this->waitFor(static fn (): bool => $workflow->refresh()->status() === 'waiting'
79447968
&& $workflow->summary()?->wait_kind === 'timer');
79457969

@@ -7957,13 +7981,17 @@ public function testCancelWithoutReasonCreatesFailureRowWithDefaultMessage(): vo
79577981

79587982
public function testCancelFailureRowAppearsInFailureSnapshots(): void
79597983
{
7984+
Queue::fake();
7985+
79607986
$workflow = WorkflowStub::make(TestTimerWorkflow::class, 'cancel-snapshots');
79617987
$workflow->start(5);
79627988

79637989
$runId = $workflow->runId();
79647990

79657991
$this->assertNotNull($runId);
79667992

7993+
$this->drainReadyTasks();
7994+
79677995
$this->waitFor(static fn (): bool => $workflow->refresh()->status() === 'waiting'
79687996
&& $workflow->summary()?->wait_kind === 'timer');
79697997

@@ -8014,6 +8042,10 @@ private function drainReadyTasks(): void
80148042
/** @var WorkflowTask|null $task */
80158043
$task = WorkflowTask::query()
80168044
->where('status', TaskStatus::Ready->value)
8045+
->where(static function ($query): void {
8046+
$query->whereNull('available_at')
8047+
->orWhere('available_at', '<=', now());
8048+
})
80178049
->orderBy('created_at')
80188050
->first();
80198051

0 commit comments

Comments
 (0)