controller_media_runner_callback
Client-side receiver for results produced by the external
media runner site.
This controller belongs to mod_base, so each client site has a callback endpoint
without installing the runner site itself.
Endpoint
The media_runner_callback dispatch accepts POST /media-runner/callback?id=<job-id>
with Content-Type: application/json and Authorization: Bearer <secret>.
The body must be a JSON object containing the runner's result envelope. Its size
is bounded by z_media_runner_protocol:callback_limit/0 before JSON decoding.
Place in the processing flow
- A client calls
z_exec:run/4with its site context. When remote processing is configured,z_media_runnerregisters the waiting process, creates a job ID and random callback secret, and builds an absolute URL using the client'smedia_runner_callbackdispatch rule. - The client submits the job to the runner using OAuth2. The job includes that
callback URL and secret. The runner queues the command, executes it in the
sandbox, and POSTs its JSON result here with
?id=<job-id>and the secret in theAuthorization: Bearer <secret>header. - This controller authenticates the callback and forwards the decoded result to
z_media_runner. The waiting client process then usesz_media_runner_protocol:unpack/2to validate the result and restore output files to the paths declared by the original caller. This controller does not execute commands or write the returned media files.
Callback authentication
The dispatch rule is anonymous deliberately: this endpoint authenticates with the
per-job callback secret, not the OAuth2 token used to submit jobs to the runner,
nor a browser session. z_media_runner keeps only the secret's hash and associates
it with the waiting process. Both the job ID and secret must match.
The request query is already parsed before is_authorized/1. Reading the job ID
there lets us reject unauthorized requests before allocating the bounded result
body. Responses have cache prevention headers; media payloads and callback secrets
are not logged.
Delivery and lifetime
HTTP 204 acknowledges delivery to the waiting process, including a result that reports a processing failure. It does not mean that output validation succeeded. Malformed JSON or a non-map result returns 400; missing or malformed credentials return 401. Unknown jobs and non-matching secrets return 410. The runner treats 410 as final and stops retrying that callback.
While the job is registered, duplicate authenticated callbacks are acknowledged without notifying the waiting process again. The registration is removed when the call finishes, times out, or its process dies. Late callbacks then return 410. Registrations are in memory on the submitting Zotonic node; cluster routing must send callbacks back to that node, and a node restart loses pending registrations.
See the media runner documentation for deployment and client configuration.