Light Dark

Tasks

Tasks are long-running, asynchronous processes on the Hot Platform. Understanding the distinction between Runs and Tasks helps you choose the right execution model for your workflow.

Runs vs Tasks

RunsTasks
DurationShort-lived, synchronousLong-running, asynchronous
TriggerHTTP requests, events, schedulesStarted from runs or other tasks
ReturnWaits for completion, returns resultReturns immediately with TaskInfo
Use caseRequest-response, event handlersBackground jobs, containers, long-lived processes

Runs

Runs are short-lived, synchronous function executions. Each run executes a Hot function to completion and returns a result. Runs are triggered by:

  • HTTP requests (API calls, webhooks)
  • Events (send, hot:call)
  • Schedules (cron, dynamic schedules)

Runs block until the function completes. See Runs, Events & Streams for details.

Tasks

Tasks are long-running, asynchronous processes. When you start a task, execution returns immediately with a TaskInfo containing the task ID and stream ID. The task runs in the background on the task worker.

There are two types of tasks:

  1. Code Tasks — Hot code with messaging (::hot::task/start, ::hot::task/send, ::hot::task/receive) and WebSocket support (::hot::ws)
  2. Container Tasks — Docker/OCI containers via ::hot::box/start

When to Use Each

ScenarioUse
Request-response, event handlers, scheduled jobsRuns
Long-running Hot code with send/receive messagingCode Tasks
Arbitrary languages, CLI tools, system binariesContainer Tasks

Task Lifecycle

Tasks move through these states:

queued → running → completed | failed | timed_out | cancelled
StateDescription
queuedTask is waiting for a worker
runningTask is executing
completedTask finished successfully
failedTask exited with an error
timed_outTask exceeded its timeout
cancelledTask was cancelled before completion

Starting Tasks

Code Tasks

Use ::hot::task/start to start a Hot function as a long-running task:

::task ::hot::task

// Start a task with no arguments
info ::task/start(::myapp/background-sync)

// Start a task with arguments
info ::task/start(::myapp/process-data, {url: "https://example.com"})

// Start with options (timeout, retry)
info ::task/start(::myapp/long-job, {input: data}, {
  timeout: 3600000,
  retry: {attempts: 3, delay: 5000, backoff: "exponential"}
})

Container Tasks

Use ::hot::box/start to run Docker/OCI containers:

::box ::hot::box

task ::box/start(BoxConf({
  image: "python:3.13-alpine",
  cmd: ["python", "-c", "print('Hello')"],
  size: "nano"
}))

See Containers for full container documentation.

TaskInfo

Both ::hot::task/start and ::hot::box/start return a TaskInfo with:

FieldTypeDescription
idStrUnique task identifier (UUID)
stream-idStrStream this task belongs to

For code tasks, TaskInfo also includes stream (the full stream object) and origin-run (the run that spawned the task).

Cancellation

Cancel a queued or running task with ::hot::task/cancel:

::task ::hot::task

info ::task/start(::myapp/long-job, data)

// Later, cancel the task
cancelled ::task/cancel(info.id)

Returns true if the task was cancelled, false if it was already in a terminal state.

For running tasks, a cancellation message is delivered to the task's receive channel (as {$cancel: true}) so it can exit cooperatively.

Messaging (Code Tasks Only)

Code tasks can receive messages from other runs or tasks using ::hot::task/send and ::hot::task/receive:

::task ::hot::task

// From a run: start a task and send it data
info ::task/start(::myapp/worker, null)
::task/send(info.id, {command: "process", payload: data})
::task/send(info.id, "shutdown")

// Inside the task function: receive messages
my-task fn (initial-args: Any): Any {
  msg ::task/receive()
  cond {
    eq(msg, "shutdown") => { "done" }
    => { process(msg) }
  }
}

receive blocks until a message arrives. Returns null when the task's inbox closes.

Checkpoint & Restore (Code Tasks)

Long-running code tasks can save application state that persists across restarts. If a task is interrupted (worker crash, deploy) and retried, the new instance can call restore() to pick up where it left off.

::task ::hot::task

my-etl fn (config: Map): Any {
  // Restore previous state, or start fresh
  state or(::task/restore(), {offset: 0, processed: 0})

  // ... process batch starting from state.offset ...

  // Save progress
  ::task/checkpoint({offset: add(state.offset, batch-size), processed: add(state.processed, batch-size)})
}

checkpoint accepts any serializable value and returns true on success. restore returns the last checkpointed value, or null if no checkpoint exists. Both are only callable from inside a task.

You can also inspect a different task's checkpoint by passing a task ID: ::task/restore(task-id).

WebSocket Support (Code Tasks)

Code tasks can maintain long-lived WebSocket connections using ::hot::ws:

::ws ::hot::ws

// Inside a task
conn ::ws/connect("wss://echo.websocket.org", {headers: {}})
::ws/send(conn, {type: "hello", text: "world"})
msg ::ws/receive(conn)
::ws/close(conn)

WebSocket connections outlive a single run, making them ideal for real-time sessions inside tasks.