Commit 27b2560
[13.x] Pop managed queue jobs from the cloud-agent instead of SQS (#60659)
* [13.x] Pop managed queue jobs from the cloud-agent instead of SQS
Route the cloud Queue decorator's pop() through the in-container
cloud-agent's unix-socket runtime API (GET /next) when the underlying
connection is an SqsQueue, building an AgentSqsJob instead of receiving
from SQS directly. Any non-SQS underlying queue is delegated to as
before.
The AgentSqsJob still deletes / releases against SQS through the
inherited SqsClient — the agent never touches the message — but also
reports each terminal outcome back to the agent via POST /result so it
can stop heartbeating the message's visibility and accept the next
invoke. The agent socket path is configurable via
LARAVEL_CLOUD_AGENT_SOCKET, mirroring LARAVEL_CLOUD_LOG_SOCKET.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* [13.x] Report managed queue job outcome to agent instead of mutating SQS
AgentSqsJob now calls the grandparent Job::delete()/release() to keep
queue:work local state correct without SqsJob's direct SQS calls; the poller
owns delete/visibility. reportResultToAgent now sends the release delay.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* [13.x] Always pop from the agent and rename AgentSqsJob to CloudJob
The cloud Queue always runs against a managed (SQS) queue, so pop() now
polls the agent unconditionally instead of branching on the underlying
queue type, inlining the former popFromAgent() helper. The agent socket
path is hardcoded to /tmp/cloud-agent.sock, and AgentSqsJob is renamed to
CloudJob to match the Cloud\Queue sibling.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* [13.x] Always report processed on delete and strip unused error from result
A terminally-failed managed queue job is deleted from SQS just like a
successful one (the base fail() routes through delete()), so CloudJob now
reports "processed" in both cases rather than a redelivery-triggering
"failed". Drops the redundant $failing flag and the fail() override since
the base markAsFailed() already runs before delete().
Also strips the unused $error field from the /result report path (the
poller never reads it), and switches the agent transport from a raw Guzzle
client to the Http facade so the pop loop can be exercised with Http::fake()
in tests, matching how FailedJobProvider already talks to the cloud.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* [13.x] Harden CloudJob agent reporting and restore overflow support (#11)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* [13.x] Harden CloudJob overflow cleanup and agent reporting (#12)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* [13.x] Make CloudJob agent poller opt-in via config
Default the managed-queue connection back to receiving jobs directly
from SQS; route pops through the in-container cloud-agent only when
agent.enabled is set.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* [13.x] Remove accidentally committed .phpactor.json
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* [13.x] Trust agent attributes and crash the worker on an unreachable agent
Drop normalizeAgentAttributes: the dispatcher receives the message from SQS,
which always returns ApproximateReceiveCount, so the agent forwards it and we
read it straight through like SqsJob::attempts() trusts SQS.
Stop rescuing requestNextFromAgent to null. An unreachable (or wedged) agent
socket means the agent is not running in the pod, which is unrecoverable, so
surface it as an AgentUnreachableException. An AgentAwareLostConnectionDetector
(wired for queue:work) treats that as a lost connection, so the worker exits and
the pod is restarted instead of idling as if the queue were empty.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* [13.x] Fall back to SQS directly when the cloud-agent is unreachable
When reporting an in-flight job's outcome, distinguish an agent that is
alive but rejecting the report (HTTP error: retain and let the retry /
teardown safety net handle it, since its poller still owns the message)
from an agent that has crashed (connection error: its poller can no
longer act, so delete()/release() operate on SQS directly via SqsJob's
real seams rather than lose the job). Receiving the next job from a
crashed agent stays fatal; this only salvages a job already in flight.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* [13.x] Read overflow config directly instead of via getOverflowStorage
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* [13.x] Remove stray whitespace in SqsQueue
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* [13.x] Own CloudJob delete/release instead of no-op overrides
Skip SqsJob's SQS calls by flagging the job via the base Job directly,
rather than overriding deleteMessageFromSqs/changeMessageVisibilityInSqs/
deleteOverflowPayload to no-ops. The delete/release logic now reads in one
place, touching SQS only on the agent-unreachable fallback.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* [13.x] Drop SQS fallback and teardown reporting from CloudJob
PHP now only reports a job's outcome to the agent; it never mutates SQS
itself. An agent that rejects a report has already finalized the job, so
the message redelivers regardless. An unreachable agent propagates as an
AgentUnreachableException — the worker treats it as a lost connection and
exits (matching the pop side), and SQS redelivers via the visibility
timeout once the crashed agent stops heartbeating.
Removes CloudJob::fallBackToSqs() and reportToAgent(), and the teardown
safety-net call in Queue::finishProcessingJob(). The WorkerStopping
listener and shutdown function stay: they flush the terminal queue
telemetry event for the last job of every worker run, which is separate
from agent reporting.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* [13.x] Make CloudJob report fire-and-trust, dropping report dedup
report() no longer tracks reportedStatus or suppresses calls to fake
idempotency / a "processed supersedes released" ordering. It reports each
outcome as the worker produces it and assumes a returned report was
accepted; the agent is the single authority on what ordering of operations
is valid.
A rejected report (RequestException) now propagates instead of being
swallowed, so an outcome the agent cannot apply surfaces rather than being
papered over. delete()'s overflow purge is therefore only reached once the
agent accepts the "processed" outcome — a thrown report leaves the payload
in place for the redelivery. Unreachable still raises
AgentUnreachableException; the message redelivers via the visibility
timeout regardless.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* [13.x] Inline match into emitted queue event type
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* [13.x] Trim verbose comments to Laravel conventions
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* [13.x] Escalate agent error and malformed responses as unreachable
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* [13.x] Treat any non-200 from GET /next as agent unreachable
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* [13.x] Use Response::ok() helper for the GET /next status check
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* [13.x] Escalate a server error from POST /result as agent unreachable
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* [13.x] Drop the pointless queue parameter from popFromAgent
The agent only receives messages, so it has no queue to pop from; each
message reports the SQS queue URL it came from. The queue parameter only
fed a fallback that never fired, so remove it.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* [13.x] Only pop from the agent for the worker's own queue
The cloud-agent sidecar long-polls a single queue on behalf of one
queue:work worker, so it only serves work when that worker is popping
the queue it was started for. Gate the agent path on running queue:work
and the requested queue matching the worker's --queue; anything else
falls back to popping from SQS directly.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* [13.x] Document single-queue agent assumption and cover argv forms
The cloud-agent serves a single queue, so a managed worker is expected
to run one. Note this on workerQueue() and add tests pinning the
space-separated --queue form and the multi-queue fallback to SQS.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* [13.x] Report the receipt handle to the agent with each job outcome
SQS reuses a message id across redeliveries, so a result matched on the
id alone could let a stale outcome finalize a re-dispatched receive. Echo
the receipt handle the agent supplied so it can pin the outcome to the
exact receive; it is omitted when absent, preserving the id-only fallback.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* [13.x] Scope the agent result retry to connection failures
Retry POST /result only on a ConnectionException, matching the method's
docblock and FailedJobProvider::find(): a 4xx/5xx is the agent's
authoritative response for the message, not a transient hiccup, so it
propagates on the first attempt rather than being re-POSTed three times
in the job-completion hot path.
Also align workerQueue() with WorkCommand's --queue fallback so an
option-less managed worker isn't silently misrouted off the agent, and
firm up the test argv save/restore and the processed-event queue
attribution coverage.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* formatting
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Taylor Otwell <taylor@laravel.com>1 parent e2a7f29 commit 27b2560
7 files changed
Lines changed: 997 additions & 49 deletions
File tree
- src/Illuminate
- Foundation/Cloud
- Queue/Jobs
- tests/Foundation/Cloud
Lines changed: 32 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
Lines changed: 10 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
8 | 12 | | |
9 | 13 | | |
| 14 | + | |
10 | 15 | | |
11 | 16 | | |
12 | 17 | | |
| |||
37 | 42 | | |
38 | 43 | | |
39 | 44 | | |
| 45 | + | |
40 | 46 | | |
41 | 47 | | |
42 | 48 | | |
| |||
185 | 191 | | |
186 | 192 | | |
187 | 193 | | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
188 | 198 | | |
189 | 199 | | |
190 | 200 | | |
191 | 201 | | |
192 | 202 | | |
193 | 203 | | |
194 | 204 | | |
195 | | - | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
196 | 208 | | |
197 | 209 | | |
198 | 210 | | |
199 | 211 | | |
200 | 212 | | |
201 | 213 | | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
| 263 | + | |
| 264 | + | |
| 265 | + | |
| 266 | + | |
| 267 | + | |
| 268 | + | |
| 269 | + | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
| 273 | + | |
| 274 | + | |
| 275 | + | |
| 276 | + | |
| 277 | + | |
| 278 | + | |
| 279 | + | |
| 280 | + | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
| 284 | + | |
| 285 | + | |
| 286 | + | |
| 287 | + | |
| 288 | + | |
| 289 | + | |
| 290 | + | |
| 291 | + | |
| 292 | + | |
| 293 | + | |
| 294 | + | |
| 295 | + | |
| 296 | + | |
| 297 | + | |
| 298 | + | |
| 299 | + | |
| 300 | + | |
| 301 | + | |
| 302 | + | |
| 303 | + | |
| 304 | + | |
| 305 | + | |
| 306 | + | |
| 307 | + | |
| 308 | + | |
| 309 | + | |
| 310 | + | |
| 311 | + | |
| 312 | + | |
| 313 | + | |
| 314 | + | |
| 315 | + | |
| 316 | + | |
| 317 | + | |
| 318 | + | |
| 319 | + | |
| 320 | + | |
| 321 | + | |
| 322 | + | |
| 323 | + | |
| 324 | + | |
| 325 | + | |
| 326 | + | |
| 327 | + | |
| 328 | + | |
| 329 | + | |
| 330 | + | |
| 331 | + | |
202 | 332 | | |
203 | 333 | | |
204 | 334 | | |
| |||
210 | 340 | | |
211 | 341 | | |
212 | 342 | | |
| 343 | + | |
| 344 | + | |
| 345 | + | |
| 346 | + | |
| 347 | + | |
| 348 | + | |
| 349 | + | |
| 350 | + | |
| 351 | + | |
| 352 | + | |
| 353 | + | |
| 354 | + | |
| 355 | + | |
| 356 | + | |
| 357 | + | |
| 358 | + | |
| 359 | + | |
| 360 | + | |
| 361 | + | |
| 362 | + | |
| 363 | + | |
| 364 | + | |
| 365 | + | |
213 | 366 | | |
214 | 367 | | |
215 | 368 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
| 8 | + | |
8 | 9 | | |
9 | 10 | | |
10 | 11 | | |
| |||
39 | 40 | | |
40 | 41 | | |
41 | 42 | | |
| 43 | + | |
42 | 44 | | |
43 | 45 | | |
44 | 46 | | |
| |||
101 | 103 | | |
102 | 104 | | |
103 | 105 | | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
104 | 112 | | |
105 | 113 | | |
106 | 114 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
67 | 67 | | |
68 | 68 | | |
69 | 69 | | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
70 | 81 | | |
71 | 82 | | |
72 | 83 | | |
| |||
83 | 94 | | |
84 | 95 | | |
85 | 96 | | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
86 | 109 | | |
87 | 110 | | |
88 | 111 | | |
| 112 | + | |
89 | 113 | | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
90 | 121 | | |
91 | 122 | | |
92 | 123 | | |
| |||
0 commit comments