Recommended model
Create one trace for each active execution attempt or short execution burst. Record these attributes on its root span and important child spans:
These are Squasher conventions for custom OpenTelemetry attributes. Do not put
credentials, full payloads, or customer content in them.
Use a low-cardinality value for
squasher.workflow.id and
squasher.workflow.step. Use run_id and checkpoint_id only for direct
search, not dashboard grouping.
Parent versus link
Use a parent-child relationship when work continues in one live causal call and you can propagate the normal trace context. Use a span link when:- a retry starts after the earlier process or trace ended
- a checkpoint resumes in a new runtime instance
- one step combines several messages or upstream runs
- one completed step starts several independent branches
Retry example
The first attempt can end with an error. The next attempt starts a new trace and links its root span to the failed attempt:Checkpoints and state changes
Record a span event when a checkpoint occurs during an active span:Status and errors
- End each attempt span when that attempt stops running.
- Set span status to
ERRORwhen an attempt fails. - Record
error.typeand a safe error message. - Record the final workflow outcome as a structured event or finite completion span.
- Keep timeout, cancellation, retry, and terminal failure as different outcomes.
Verify
- Run one workflow that pauses and resumes.
- Run one workflow that fails once and then succeeds.
- Search by
squasher.workflow.run_idand confirm every attempt appears. - Open the retry span and confirm its link opens the earlier attempt.
- Confirm that no span remains open only because the workflow is waiting.