Python handler reference
Handler contract for Coderunner Python functions, background jobs, and scheduled jobs.
Applies to the function, job, and schedule workload types — code you upload as a ZIP and Code Runner executes against a Python bootstrap image. For a service (any container, your own Dockerfile), see Deploy a container image instead — there's no handler contract there, just a container listening on a port.
Project structure
my-coderunner/
├── handler.py
└── requirements.txtThe entry point must be a function named handler inside handler.py — Code Runner invokes handler(context, payload) directly.
Handler contract
def handler(context, payload):
# ...
pass| Type | Signature | Return value |
|---|---|---|
function | def handler(context, payload) | {"statusCode": ..., "body": ..., "headers": ...} — required. A function is a request/response HTTP handler; whatever you return becomes the response. |
job / schedule | def handler(context, payload) | None required — the process runs to completion and exits. Log via print(); there's no response to return. |
payload is the JSON dict supplied by the caller (function) or trigger (job/schedule). context is runtime-provided; no properties are documented yet beyond its presence in the signature — don't depend on undocumented context fields.
Minimal example (function)
def handler(context, payload):
try:
if not payload or "name" not in payload:
return {
"statusCode": 400,
"body": {"error": "Name is required"},
"headers": {"content-type": "application/json"},
}
return {
"statusCode": 200,
"body": {"message": f"Hello {payload['name']}"},
"headers": {"content-type": "application/json"},
}
except Exception as err:
print(f"Function failed: {err}")
return {
"statusCode": 500,
"body": {"error": "Internal server error"},
"headers": {"content-type": "application/json"},
}A job/schedule handler looks the same minus the return — do the work, print, and let the function end:
def handler(context, payload):
try:
print("Background job started")
do_something(payload)
print("Background job completed successfully")
except Exception as err:
print(f"Background job failed: {err}")External packages
Declare PyPI dependencies in requirements.txt:
requestsEnvironment variables and secrets
os.environ.get("NAME") reads deploy-time env vars (gf deploy -e KEY=value) and injected secrets (gf deploy --secret KEY, see Secrets). Never hard-code API keys, passwords, or connection strings — and never zip a .env file.
import os
api_key = os.environ.get("API_KEY")Common status codes (function)
| Code | Usage |
|---|---|
200 | Successful execution |
201 | Resource created |
400 | Invalid or missing input |
401 / 403 | Auth required / denied |
404 | Not found |
500 | Unexpected error — don't leak exception internals in the body |
Best practices
- Expose the entry point as exactly
handler(context, payload). - Access
payloadsafely with.get()rather than direct indexing. - Wrap risky operations in
try/except; don't let an unhandled exception crash-loop the container. - Use
print()for logs — stdout/stderr are captured as Process Log output. - Keep secrets out of the ZIP — inject them at deploy time.
Related
- Coderunner — workload types and lifecycle
- Deploy a container image — the
servicetype instead - Node.js handler reference · .NET handler reference