Schedule handler #
A schedule handler receives one HTTP request for a declared schedule's due instant. This reference brings together its request headers, response outcomes, and the check that keeps the handler private.
Request headers #
The platform sends one POST with an empty body to the declared path. The serving router alone sets these four headers:
| Header | Value |
|---|---|
x-turnzero-cloud-invocation |
schedule |
x-turnzero-cloud-schedule |
The schedule's name. |
x-turnzero-cloud-run |
The run identifier. |
x-turnzero-cloud-schedule-due |
The due instant in ISO 8601 form in UTC, to the millisecond, such as 2026-10-08T05:00:00.000Z. |
The router never passes a client's copies of these headers to the application. The platform checks the request before the handler runs; there is no signature or token for the handler to verify. Never log or echo other x-turnzero-cloud- headers, or log a request's headers whole. The platform removes the router's mark before the handler runs.
Private-path check #
On a deployed copy, the Node.js Runtime harness first checks the router's mark. An unmarked request is refused 403 router_mark_required; a loopback request is exempt from that mark check.
After that check passes, a request on a declared handler path without the router-set invocation header receives 404 scheduled_handler_only. The harness refuses it before application code runs, so the declared handler path is not a public endpoint.
Keep a handler's own check where a framework routes more widely than the exact declared path, such as a prefix or wildcard mount. A handler without the Schedule package's router checks for x-turnzero-cloud-invocation: schedule and returns 404 otherwise.
The Schedule router checks its declared paths. Its readScheduledRun(headers) returns no run unless all four headers are present exactly once. The plain Node.js handler shows the check without the package.
On your machine, use the package's test double or local request recipe. A local run loads no runtime harness.
Response status and outcome #
The platform records the handler's HTTP status and the run's outcome separately:
| What happens | Recorded outcome | What to do |
|---|---|---|
| The handler responds with a 2xx status inside the window. | succeeded |
End the response after the work finishes. |
| The handler responds with any other status, including 3xx, 4xx, or 5xx. | failed |
Put the reason in the response body; the platform keeps its first bytes. |
| The upstream fails after the router starts the request. | failed |
Read the run's detail and application logs. |
| The request reaches its execution window before completion. | window_ended |
Stop work when the request's abort signal fires. |
With the Schedule package, a handler that returns nothing gets a 200 response. A handler may return a status and body or end the response itself. If it throws, the package router responds 500 handler_failed.
The window is 230 seconds by default. Read its current length as window_seconds in submit_manifest or read_schedules. Waking a stopped environment spends part of that window. A response sent after the window ends cannot change the outcome. Start no timer, polling loop, or child process that outlives the response.
Repeats and runs that never reach the handler #
The platform retries no run. Make the handler safe to repeat for the same schedule name and due instant, using a record in storage or a declared database. The Schedule package supplies that pair as run.key; a run identifier alone does not identify the due instant.
A due time while the previous run remains in flight is skipped, never queued. Named application admission refusals also record skipped: the application is unknown or undeployed, its owner is suspended, or its monthly backend-action or data-transfer limit is exceeded. The run's detail gives the reason.
Failure to reach the router, an invoke-secret refusal, or a router failure before it can forward the request records unreachable. A due time too old to start is missed. A run left without a recorded end after its window is abandoned, whose outcome is unknown.
These outcomes are not HTTP responses from the handler. For declaration, deployment, halt, and quota refusals, use Add a scheduled job: Refusals and the refusals reference.
Related #
- Add a scheduled job declares, deploys, and checks a job, including a manual run.
- Run scheduled work describes the declaration and when it starts in each environment.
- Schedule describes the package's router, handlers, and test double.
- Read logs and counters reads the platform's run events and the handler's console.