VertexImpl Lifecycle
VertexImpl is the AM-side representation of a single Vertex in a running
DAG. Its lifecycle is a Hadoop state machine with ~15 states and dozens of
events. This chapter walks the happy path (NEW → SUCCEEDED), the major
failure and kill paths, and the rules that govern transitions.
After this chapter you should be able to draw the state machine on a whiteboard and predict every state transition for any event in any state.
File
tez-dag/src/main/java/org/apache/tez/dag/app/dag/impl/VertexImpl.java
This is one of the largest files in Tez (typically 4000+ lines). Skim once
top-to-bottom, then read the stateMachineFactory block carefully.
grep -n "stateMachineFactory" \
tez-dag/src/main/java/org/apache/tez/dag/app/dag/impl/VertexImpl.java | head
The factory is a single chained builder defined near the top of the file (roughly 200–600 lines depending on version).
The states
grep -n "VertexState\." tez-dag/src/main/java/org/apache/tez/dag/app/dag/impl/VertexImpl.java | head
# or
grep -n "public enum\|enum VertexState" \
tez-api/src/main/java/org/apache/tez/dag/api/event/VertexState.java \
tez-dag/src/main/java/org/apache/tez/dag/app/dag/impl/VertexImpl.java
The full state set (names exact as of 0.10.x):
| State | Meaning |
|---|---|
NEW | Just constructed; no events seen |
INITIALIZING | Inputs being initialized (e.g., split generation) |
INITED | Ready to run; awaiting V_START |
RUNNING | Tasks executing |
COMMITTING | All tasks succeeded; outputs being committed |
SUCCEEDED | Terminal: all good |
TERMINATING | Failure/kill in progress; awaiting task drain |
KILLED | Terminal: killed externally |
FAILED | Terminal: failed (own fault) |
ERROR | Terminal: AM internal error |
RECOVERING | (Recovery only) replaying events into this vertex |
State × event matrix (happy path)
| State | Event | Next state | Action |
|---|---|---|---|
| NEW | V_INIT | INITIALIZING | construct inputs, kick off InputInitializers |
| INITIALIZING | V_ROOT_INPUT_INITIALIZED | INITIALIZING | accumulate events; if all done → INITED |
| INITIALIZING | V_ROOT_INPUT_FAILED | TERMINATING | bubble failure |
| INITIALIZING | V_INIT_COMPLETED | INITED | finalize parallelism if not set |
| INITED | V_START | RUNNING | schedule tasks via VertexManagerPlugin |
| RUNNING | V_TASK_COMPLETED (success) | RUNNING | bump counter; if all done → COMMITTING |
| RUNNING | V_TASK_COMPLETED (final fail) | TERMINATING | initiate cleanup |
| RUNNING | V_TASK_RESCHEDULED | RUNNING | rerun a task |
| COMMITTING | V_COMMIT_COMPLETED | SUCCEEDED | publish history |
| COMMITTING | V_COMMIT_FAILED | TERMINATING | rerun or fail |
For the complete matrix, count the addTransition(...) calls:
grep -c "addTransition" \
tez-dag/src/main/java/org/apache/tez/dag/app/dag/impl/VertexImpl.java
There are usually >100 transitions registered. Each carries a one-line comment with the bug or JIRA that motivated it; read those comments.
Failure path walk
stateDiagram-v2
[*] --> NEW
NEW --> INITIALIZING: V_INIT
INITIALIZING --> INITED: V_INIT_COMPLETED
INITIALIZING --> TERMINATING: V_ROOT_INPUT_FAILED
INITED --> RUNNING: V_START
RUNNING --> COMMITTING: all tasks SUCCEEDED
RUNNING --> TERMINATING: any task FAILED beyond max-attempts
RUNNING --> TERMINATING: V_TERMINATE
COMMITTING --> SUCCEEDED: V_COMMIT_COMPLETED
COMMITTING --> TERMINATING: V_COMMIT_FAILED
TERMINATING --> FAILED
TERMINATING --> KILLED
SUCCEEDED --> [*]
FAILED --> [*]
KILLED --> [*]
TERMINATING exists because a vertex cannot just jump to FAILED — it must
first kill all running tasks and clean up its outputs. The transition from
TERMINATING to a terminal state happens when the task count reaches zero.
Vertex initialization in detail
V_INIT is the most complex transition. The handler must:
- Construct each root
InputDescriptorand call itsInputInitializer. - If parallelism is
-1, defer task creation until either theVertexManagerPlugincallsreconfigureVertex(...)or the root inputs report concrete counts. - Construct downstream
Edgeobjects (the AM-sideEdge, not thetez-apione) and bind theirEdgeManagers. - Schedule the
VertexManagerPlugin.onVertexStartedcallback (it fires onV_START, notV_INIT).
Read the body:
grep -n "InitTransition\|RootInputInitTransition\|RECOVERING" \
tez-dag/src/main/java/org/apache/tez/dag/app/dag/impl/VertexImpl.java | head -20
The commit path
A vertex with a DataSink (an OutputCommitter) must run a commit phase
after all tasks succeed. The commit:
- Runs on the AM (not in tasks).
- May fail and trigger a rerun (
V_COMMIT_FAILED → TERMINATING). - Holds the vertex in
COMMITTINGfor the duration.
Vertex-group commit (when multiple vertices write to a shared VertexGroup)
is coordinated by DAGImpl; individual VertexImpls just signal that they
are ready to commit.
grep -n "CommittingTransition\|commitOutput\|OutputCommitter" \
tez-dag/src/main/java/org/apache/tez/dag/app/dag/impl/VertexImpl.java | head
Reading exercise
# State machine block
sed -n '1,500p' tez-dag/src/main/java/org/apache/tez/dag/app/dag/impl/VertexImpl.java
# Count transitions
grep -c "addTransition" tez-dag/src/main/java/org/apache/tez/dag/app/dag/impl/VertexImpl.java
# Find every event that can take the vertex to FAILED
grep -n "VertexState.FAILED" tez-dag/src/main/java/org/apache/tez/dag/app/dag/impl/VertexImpl.java | head
# Find the InitTransition body
grep -n "private.*class.*Transition\b" tez-dag/src/main/java/org/apache/tez/dag/app/dag/impl/VertexImpl.java | head
Answer:
- List five events that can take the vertex from
RUNNINGtoTERMINATING. - What determines the final state (
FAILEDvsKILLED) onceTERMINATINGcompletes? - Why is
INITEDdistinct fromRUNNING— what doesV_STARTactually trigger? - How is parallelism set when a vertex starts with
parallelism = -1? - What happens to in-flight tasks when a vertex transitions to
TERMINATING? - Why does the state machine have a separate
COMMITTINGstate instead of committing insideRUNNING?
Common bugs and symptoms
| Symptom | Root cause | Where to look |
|---|---|---|
InvalidStateTransitonException: Invalid event V_TASK_COMPLETED at SUCCEEDED | A late task completion event arrived after vertex completed (race) | Check task retry logic; add a no-op transition |
Vertex stuck in INITIALIZING forever | Root input initializer never emitted events | Check InputInitializerEvents in log; cross-check initializer impl |
Vertex transitions to FAILED but the failing task was killed externally | Bug in TaskAttemptImpl setting the wrong termination cause | See task-attempt-lifecycle.md |
All tasks succeed but vertex stays in COMMITTING | Output committer hangs | Check committer for synchronous slow I/O; consider async |
Recovery replays into RUNNING but tasks aren't relaunched | Missing recovery event for in-flight tasks | Look for VertexTaskStartEvent gaps in recovery log |
V_KILL causes vertex to stay in TERMINATING with one task lingering | Container heartbeat timeout > kill deadline | Tune tez.task.timeout-ms |
Validation: prove you understand this
- From memory, list all 10–11
VertexStatevalues with a one-line meaning. - Without running code, predict the next state for: (NEW, V_TERMINATE), (INITIALIZING, V_TERMINATE), (RUNNING, V_TASK_RESCHEDULED), (COMMITTING, V_TASK_RESCHEDULED). Verify against the source.
- Find the JIRA reference next to one transition you don't understand; read the JIRA; come back and explain why the transition exists.
- Write a unit test that drives a
VertexImplfromNEWtoSUCCEEDEDusingDrainDispatcher. (UseTestVertexImplas a template.) - Modify
VertexImplto add a no-op transition for some(state, event)pair currently absent; updateTestVertexImplin the same patch. Compile.