Task Lifecycle

AEP Task Lifecycle

> Status: draft. Part of the AEP 0.1 protocol specification.

Purpose

Define the lifecycle of long-running asynchronous tasks. A task is a unit of work that may span multiple events and take an arbitrary amount of time to complete.

Task States

                ┌─────────┐
                │SUBMITTED│
                └────┬────┘
                     │
                ┌────▼────┐
                │ACCEPTED ├────────────────────────┐
                └────┬────┘                        │
                     │                              │
                ┌────▼────┐                         │
           ┌────┤ STARTED ├────┐                    │
           │    └────┬────┘    │                    │
           │         │         │                    │
      ┌────▼───┐ ┌───▼────┐ ┌─▼──────┐             │
      │BLOCKED │ │PROGRESS│ │ OUTPUT │             │
      └────┬───┘ └───┬────┘ └─┬──────┘             │
           │         │         │                    │
           └─────────┴─────────┘                    │
                     │           ┌──────────┬───────┘
          ┌──────────┼───────────┤          │
          │          │           │          │
     ┌────▼──┐ ┌─────▼────┐ ┌───▼───┐ ┌───▼───────┐
     │FAILED │ │COMPLETED │ │CANCELLED│ │ TIMED_OUT │
     └───────┘ └──────────┘ └────────┘ └───────────┘

State Transitions

FromToEventNotes
SUBMITTEDtask.submittedInitial state
SUBMITTEDACCEPTEDtask.acceptedProducer accepts the task
SUBMITTEDFAILEDtask.failedPre-validation failure
SUBMITTEDCANCELLEDtask.cancelledCancelled before acceptance
SUBMITTEDTIMED_OUTtask.timed_outExpired before acceptance
ACCEPTEDSTARTEDtask.startedWork begins
ACCEPTEDFAILEDtask.failedFailed before starting
ACCEPTEDCANCELLEDtask.cancelledCancelled before starting
ACCEPTEDTIMED_OUTtask.timed_outExpired before starting
STARTEDPROGRESStask.progressIntermediate progress report
STARTEDOUTPUTtask.outputPartial output produced
STARTEDBLOCKEDtask.blockedWaiting for dependency
STARTEDCOMPLETEDtask.completedTask finished successfully
STARTEDFAILEDtask.failedTask failed during execution
STARTEDCANCELLEDtask.cancelledCancelled during execution
STARTEDTIMED_OUTtask.timed_outExceeded deadline
BLOCKEDSTARTEDtask.startedResumed after unblocking
BLOCKEDPROGRESStask.progressProgress while blocked
BLOCKEDFAILEDtask.failedFailed while blocked
BLOCKEDCANCELLEDtask.cancelledCancelled while blocked
BLOCKEDTIMED_OUTtask.timed_outExpired while blocked
PROGRESSPROGRESStask.progressRepeated progress updates
PROGRESSOUTPUTtask.outputPartial output
PROGRESSBLOCKEDtask.blockedBlocked during progress
PROGRESSCOMPLETEDtask.completedTask finished
PROGRESSFAILEDtask.failedFailed during progress
PROGRESSCANCELLEDtask.cancelledCancelled during progress
PROGRESSTIMED_OUTtask.timed_outExpired during progress
OUTPUTPROGRESStask.progressMore progress after partial output
OUTPUTOUTPUTtask.outputAdditional partial output
OUTPUTBLOCKEDtask.blockedBlocked after partial output
OUTPUTCOMPLETEDtask.completedFinal output = completion
OUTPUTFAILEDtask.failedFailed after partial output
OUTPUTCANCELLEDtask.cancelledCancelled after partial output
OUTPUTTIMED_OUTtask.timed_outExpired after partial output

Terminal states: COMPLETED, FAILED, CANCELLED, TIMED_OUT.

Task Events

All task events share a common envelope pattern:

{
  "type": "task.<action>",
  "task_id": "task_01",
  "payload": {
    "task_id": "task_01",
    "state": "<current_state>"
  }
}

task.submitted

Initiates a task. Sent by the consumer or orchestrator.

{
  "type": "task.submitted",
  "task_id": "task_01",
  "payload": {
    "task_id": "task_01",
    "description": "crawl example.org",
    "timeout_ms": 300000,
    "priority": "normal"
  }
}

Optional payload fields: description, timeout_ms, priority.

task.accepted

Producer confirms it will execute the task.

task.started

Producer has begun execution.

task.progress

Intermediate progress update.

{
  "type": "task.progress",
  "task_id": "task_01",
  "payload": {
    "task_id": "task_01",
    "state": "progress",
    "message": "Indexed 120 of 500 pages",
    "progress": 0.24
  }
}

Optional payload fields: message (string), progress (number 0..1).

task.output

Partial or streaming output from an in-progress task.

task.blocked

Task cannot proceed until a dependency is resolved.

{
  "type": "task.blocked",
  "task_id": "task_01",
  "payload": {
    "task_id": "task_01",
    "state": "blocked",
    "reason": "waiting for memory indexing"
  }
}

task.completed

Task finished successfully.

{
  "type": "task.completed",
  "task_id": "task_01",
  "payload": {
    "task_id": "task_01",
    "state": "completed",
    "result": { "pages_indexed": 500 }
  }
}

The result field carries the task's final output.

task.failed

Task execution failed.

{
  "type": "task.failed",
  "task_id": "task_01",
  "payload": {
    "task_id": "task_01",
    "state": "failed",
    "error": {
      "code": "tool_error",
      "message": "crawler returned HTTP 503",
      "retryable": true
    }
  }
}

task.cancelled

Task was cancelled, either by the consumer or the producer.

{
  "type": "task.cancelled",
  "task_id": "task_01",
  "payload": {
    "task_id": "task_01",
    "state": "cancelled",
    "reason": "user requested cancellation"
  }
}

task.timed_out

Task exceeded its configured timeout.

{
  "type": "task.timed_out",
  "task_id": "task_01",
  "payload": {
    "task_id": "task_01",
    "state": "timed_out",
    "error": {
      "code": "task_timeout",
      "message": "task task_01 timed out",
      "retryable": true
    }
  }
}

Cancellation Protocol

Cancellation is a two-phase process:

1. Request: Consumer sends task.cancel.requested (note: distinct event type from task.cancelled). 2. Confirm: Producer sends task.cancelled after stopping work and cleaning up.

The task may still produce events between the request and confirmation. Consumers must handle this.

Timeout Semantics

A timeout_ms value in task.submitted sets a deadline. The producer is responsible for sending task.timed_out if the task does not reach a terminal state within the deadline.

A producer may also apply a default timeout for tasks without an explicit timeout_ms.

Implementation Notes