Fix #67: dispatch CircuitFailed when an asynchronous task ends without a result - #91
Open
corgab wants to merge 2 commits into
Open
Fix #67: dispatch CircuitFailed when an asynchronous task ends without a result#91corgab wants to merge 2 commits into
corgab wants to merge 2 commits into
Conversation
… result The asynchronous flow announced success through CircuitCompleted but had no event for the three ways a dispatched task can end without a result: the backend reports FAILED or CANCELLED, the polling budget runs out, or the task completes without counts. Application code could only react to those by reading failed_jobs. PollQuantumTask now dispatches Aether\Events\CircuitFailed, carrying the driver, the circuit, the task ARN, the last status read and the reason, right before throwing in each of those branches; the exception still propagates so the job fails as before. Quantum::fake() mirrors it, once per task, when a stubbed Failed or Cancelled status is polled. The README events table, the asynchronous section and the fake section document it. Closes #67
Dispatching CircuitFailed from Quantum::fake() as well as from the polling job made a job run against the fake announce the failure twice, and the fake never dispatched CircuitCompleted either; the fake now only reports the stubbed status, as a real backend would, and both events belong to the job. The event's status is no longer nullable, since every producer knows it, and a listener that throws is reported and swallowed so the job still fails with the task exception whose message carries the ARN. Class docblocks and docs describe the final behaviour.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The asynchronous flow announced success through
CircuitCompletedbut had no event for the three ways a dispatched task ends without a result: the backend reportsFAILED/CANCELLED(TaskFailedException), the polling budget is exhausted (QuantumExecutionException::pollingExhausted), or the task completes without counts (QuantumExecutionException::malformedResponse). In each casePollQuantumTask::handle()threw and the only trace was a row infailed_jobs, which is not an application-level API. Laravel exposes both sides of its own asynchronous primitives (JobFailednext toJobProcessed,NotificationFailednext toNotificationSent); this package now does the same.Plan
CircuitFailedevent with the payload the issue asks for and dispatch it from the polling job right before each throw, through the injectedDispatcherlikeCircuitCompleted. Keep the exceptions so the job still fails and is recorded.CircuitCompleted.One deliberate departure from the issue text:
Quantum::fake()does not dispatchCircuitFaileditself. The fake is a device, and neither event belongs to a device:CircuitCompletedis already dispatched only by the job, and a job run against the fake (the documented way to test the async flow) would otherwise announce the failure twice. The fake keeps reporting the stubbed status, and the job dispatches exactly oneCircuitFailed; a test covers that count.Changes
src/Events/CircuitFailed.php(new):driver,circuit,taskArn,status(TaskStatus, never null:FAILED/CANCELLED, the last non-terminal status when the budget ran out, orCOMPLETEDfor a task without counts),reason(the exception message).PollQuantumTask: the three failure branches go through a privateabandonTask()that persists the state, dispatchesCircuitFailedand throws. A listener that throws is reported and swallowed, so the job still fails with the task exception whose message carries the ARN. Class docblock updated.QuantumFake::respondWithTaskStatus()docblock states that the events belong to the polling job.Quantum::fake()paragraph explaining the single dispatch. CLAUDE.md gains one conventions bullet.No config change, no new dependencies, no change to what the job throws or persists.
Tests
PollQuantumTaskTest:CircuitFaileddispatched (driver, ARN, circuit, status, reason) andCircuitCompletednot dispatched forFailedandCancelled; dispatched withRunningwhen the budget is exhausted; dispatched withCompletedand a "no measurement counts" reason on null counts; not dispatched on success.tests/Feature/CircuitFailedEventTest.php(new): the job run againstQuantum::fake()dispatches exactly oneCircuitFailedforFailedandCancelled; polling the fake directly dispatches nothing; a throwing listener does not replace theTaskFailedException.main(the event class does not exist).Local: pint passed, pest 800 tests passed.
Closes #67