Handler Overview
TaskDaemon handlers are containerized programs that process tasks. They communicate via a simple JSON protocol over stdin/stdout, making it possible to write handlers in any programming language.
How Handlers Work
TaskDaemon Handler Container
│ │
│──── JSON task ──────────────▶│ (stdin)
│ │
│ Process task
│ │
│◀─── JSON result ────────────│ (stdout)
│ │
- TaskDaemon sends a JSON task to the handler’s stdin
- Handler processes the task
- Handler writes a JSON result to stdout
- TaskDaemon captures the result
Protocol
{
"task_id": "550e8400-e29b-41d4-a716-446655440000",
"task_type": "process",
"task_data": {"key": "value"},
"attempt": 1
}
Output (stdout)
Success:
{"status": "success", "result": {"processed": true}}
Error (retryable):
{"status": "error", "error": "Connection timeout", "retryable": true}
Error (permanent):
{"status": "error", "error": "Invalid input", "retryable": false}
Official SDKs
We provide SDKs that handle the protocol for you:
Handler Requirements
Read JSON from stdin
Handler must continuously read line-delimited JSON from stdin
Process the task
Parse the task data and perform the work
Write JSON to stdout
Output a single JSON line with status and result
Flush output
Ensure stdout is flushed after each response
Print statements are safe. TaskDaemon automatically skips non-JSON lines in handler output, so print() statements for debugging won’t break the protocol. However, for production use, logging to stderr is recommended.
Logging to stderr
For production handlers, log to stderr instead of stdout to keep logs separate from the JSON protocol:
Python
Node.js
Go
Rust
Java
C#
C++
import sys
print("Debug info", file=sys.stderr)
# Or use logging
import logging
logging.basicConfig(stream=sys.stderr)
logging.info("Processing task")
console.error("Debug info");
// Or use process.stderr directly
process.stderr.write("Processing task\n");
import "os"
fmt.Fprintln(os.Stderr, "Debug info")
// Or use log package (defaults to stderr)
log.Println("Processing task")
eprintln!("Debug info");
// Or use tracing/log crates configured for stderr
System.err.println("Debug info");
// Or use a logger configured for stderr
Console.Error.WriteLine("Debug info");
std::cerr << "Debug info" << std::endl;
Minimal Example
Here’s the simplest possible handler in Python:
import json
import sys
for line in sys.stdin:
task = json.loads(line)
result = {"echo": task["task_data"]}
print(json.dumps({"status": "success", "result": result}), flush=True)
Dockerfile
Handlers must be packaged as Docker images. Make sure to install the SDK from the package manager:
FROM python:3.11-slim
RUN pip install --no-cache-dir taskdaemon
COPY handler.py /app/
WORKDIR /app
CMD ["python", "-u", "handler.py"]
Always use unbuffered output (-u flag in Python, flush=True, etc.) to ensure responses are sent immediately.
Configuration
Register handlers in handlers.toml:
[handlers.myhandler]
image = "my-handler:latest"
instances = 4
timeout = 30
handler_selection = "round-robin"
See handlers.toml configuration for all options.