Interface AsyncJobsMixin
- All Known Implementing Classes:
JobsRest
An implementing resource supplies its AsyncJobRegistry via asyncJobRegistry() — typically a
single per-process instance — and gets two endpoints for free:
GET /juneau-jobs/{jobId}/stream— a held-opentext/event-streamof the job's progress, terminated by oneresultevent carrying the terminalActionResult. Eachprogressevent carries an SSE id; a fresh attach is live-only, and aLast-Event-IDheader orlastEventIdquery parameter resumes from a position (seestreamJob(String, RestRequest, RestResponse)).POST /juneau-jobs/{jobId}/cancel— cancels the job and returns its terminalActionResult(acancelled/cancelled-after-effectoutcome).
Authorization: the stream URL is the capability
The stream is a held-open GET, so LoopbackBoundary applies only
its Host check (DNS-rebinding stays covered on every request); the Origin/CSRF/JSON checks apply to non-safe
methods only. A browser EventSource cannot set an X-Csrf-Token header and cookies are unsound on a
loopback port, so CSRF-on-GET is not an available control. Access is therefore gated by the unguessability of
the jobId path segment — an 256-bit
SecureRandom capability — and nothing else. An unknown id answers 404 (a miss
is indistinguishable, so the id space cannot be enumerated); a job already at its subscriber cap answers
429. A resume value grants nothing: it only picks a position inside a job the caller already holds the
capability for, and it is checked only after the 404, so a bad value cannot reveal whether a job exists.
Server-side hard limits
Every limit is enforced in AsyncJob / AsyncJobRegistry, not here and not on the client: the hard
timeout, the per-job output cap, the concurrent-job cap and the per-job subscriber cap. The stream loop simply
drains the job until it is terminal, which the timeout guarantees will happen.
Example:
See Also:
- Since:
- 10.0.0
-
Field Summary
FieldsModifier and TypeFieldDescriptionstatic final StringThe URL path template of the cancel endpoint.static final StringThe URL path prefix for the async-job endpoints (relative to the host mount).static final StringThe URL path template of the SSE progress stream.static final DurationHow long the stream loop blocks per poll while a job is still running (a liveness tick, not a timeout). -
Method Summary
Modifier and TypeMethodDescriptionReturns theAsyncJobRegistrybacking this resource's async jobs.default ActionResultcancelJob(String jobId, RestResponse res) [POST /juneau-jobs/{jobId}/cancel] — cancel a job and return its terminal result.static StringcancelPath(String jobId) Builds the servlet-relative cancel path for a job id.default voidstreamJob(String jobId, RestRequest req, RestResponse res) [GET /juneau-jobs/{jobId}/stream] — stream a job's progress as Server-Sent Events.static StringstreamPath(String jobId) Builds the servlet-relative stream path for a job id.
-
Field Details
-
JOBS_PREFIX
The URL path prefix for the async-job endpoints (relative to the host mount).- See Also:
-
STREAM_PATH
The URL path template of the SSE progress stream.- See Also:
-
CANCEL_PATH
The URL path template of the cancel endpoint.- See Also:
-
STREAM_POLL_INTERVAL
How long the stream loop blocks per poll while a job is still running (a liveness tick, not a timeout).
-
-
Method Details
-
asyncJobRegistry
Returns theAsyncJobRegistrybacking this resource's async jobs.- Returns:
- The registry. Never
null .
-
streamJob
default void streamJob(@Path("jobId") String jobId, RestRequest req, RestResponse res) throws IOException [GET /juneau-jobs/{jobId}/stream] — stream a job's progress as Server-Sent Events.Streams progress as
progressevents, then sends exactly oneresultevent carrying the terminalActionResultas JSON and closes. The progress event taken from the job's buffered eventiis always sent with SSE idi+1; theresultevent has no id, so a browser's last-event-ID stays at the last progress event.The start position comes from a resume value, in this order:
- The
Last-Event-IDheader, if non-empty after trimming (a browser's own reconnect re-sends the same URL, query included, and adds this header). - Otherwise the
lastEventIdquery parameter, if non-empty after trimming (an explicit opt-in to the buffered history;lastEventId=0replays everything). - Otherwise none: a fresh attach is live-only and sends only progress produced after it attached.
kresumes with buffered eventk(idk+1). A malformed value (anything but 1 to 10 ASCII digits after trimming SP/HTAB) or one past the end of the buffer is a400. An ended job still sends itsresulton every attach.Access is gated solely by the unguessable
jobId(see the interface javadoc). The checks run in this order: an unknown id is a404; a bad resume value is a400; a job already at its subscriber cap is a429. The cursor is fixed before the subscriber slot is taken, so a400never holds a slot.- Parameters:
jobId- The job's unguessable capability id.req- The REST request (for the resume value).res- The REST response.- Throws:
IOException- If the stream could not be written.
- The
-
cancelJob
[POST /juneau-jobs/{jobId}/cancel] — cancel a job and return its terminal result.A non-safe POST, so the boundary applies its full Origin/CSRF/JSON checks. Cancellation is enforced server-side (a client cannot be trusted to stop the work); the returned outcome distinguishes
cancelledfromcancelled-after-effect. An unknown id is a404carrying a named refusal.- Parameters:
jobId- The job's unguessable capability id.res- The REST response.- Returns:
- The job's terminal
ActionResult.
-
streamPath
Builds the servlet-relative stream path for a job id.- Parameters:
jobId- The job's capability id.- Returns:
- The stream path, e.g.
/juneau-jobs/<id>/stream.
-
cancelPath
Builds the servlet-relative cancel path for a job id.- Parameters:
jobId- The job's capability id.- Returns:
- The cancel path, e.g.
/juneau-jobs/<id>/cancel.
-