Skip to content

feat: report task duration on job outcomes - #504

Merged
pratyush618 merged 6 commits into
masterfrom
feat/outcome-duration
Jul 23, 2026
Merged

feat: report task duration on job outcomes#504
pratyush618 merged 6 commits into
masterfrom
feat/outcome-duration

Conversation

@kartikeya-27

@kartikeya-27 kartikeya-27 commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Closes #483.

Java exposed only raw timestamps, so every consumer recomputed elapsed time by hand. The
cause sat one layer down: the worker does measure execution time and puts
wall_time_ns on the JobResult, but Scheduler::handle_result spent it on
record_metric and returned a ResultOutcome carrying no timing at all. No shell could
report a job's duration without timing the run a second time.

ResultOutcome now carries wall_time_ns on every variant, and each SDK surfaces it.

Core

wall_time_ns on Success / Retry / DeadLettered / Cancelled, populated at every
construction site including the batch-success path. 0 is the contract's "not measured"
— a job that failed before it ever executed, or one the core recovered rather than a
worker finishing it. Every shell maps 0 to its own absent value, so an unmeasured run
never reads as an instant one.

Java

  • OutcomeEvent.durationMs()Long, null when unmeasured. The existing 6-arg
    constructor stays, delegating with 0.
  • NodeSnapshot.durationMs() and compensationDurationMs() — computed from the
    timestamps already on the snapshot, null until the leg has both started and finished.
  • TaskContext.elapsedMs() — monotonic, so after/onError hooks stop hand-rolling a
    timer in the attributes map.
  • WorkerBridge.onOutcome takes a trailing long wallTimeNs; the JNI descriptor must
    match exactly, so this is a signature change rather than an overload.

Node

JsOutcome.duration_ms flows into OutcomeEvent.durationMs.

Python

duration_ms on the retry/dead/cancelled payloads (from the outcome) and on
completed/failed (from the perf_counter start the task body already keeps), so one
duration field is present on every job event regardless of which side emits it.

Verification

  • cargo test --workspace green; --features postgres and --features redis check clean.
  • Java ./gradlew build green — spotless, strict javadoc, tests. reportsHowLongTheTaskRan
    proves the duration over the real JNI path: a 60ms task reports >= 50ms on both the
    outcome event and the middleware context.
  • Node: 470 tests, typecheck and biome clean.
  • Python: 1294 passed / 7 skipped; ruff and mypy clean.

Out of scope

Webhook bodies and the dashboard workflow-node payload are cross-SDK wire contracts —
adding a duration there needs all shells moved together, so they are untouched here.

Summary by CodeRabbit

  • New Features

    • Added execution-duration reporting to job outcome events across Node, Python, and Java SDKs.
    • Added workflow node duration and compensation-duration helpers in Java.
    • Added Java task-context elapsed-time reporting for middleware.
    • Added a dedicated reason for jobs dead-lettered after exhausting retries.
  • Documentation

    • Updated event and workflow documentation with duration fields, examples, and cases where timing is unavailable.
  • Tests

    • Added coverage for duration reporting across outcomes, events, middleware, and workflow nodes.

@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Changes

Task duration reporting

Layer / File(s) Summary
Core outcome duration contract
crates/taskito-core/...
ResultOutcome variants now carry worker-measured wall_time_ns; retry-budget exhaustion uses dedicated DLQ metadata, with scheduler propagation tests.
Java outcome transport and event timing
crates/taskito-java/..., sdks/java/src/main/java/..., sdks/java/test-support/...
JNI and Java bridge callbacks pass wall time into OutcomeEvent, while the in-memory backend measures dispatch elapsed time.
Node and Python duration payloads
crates/taskito-node/..., crates/taskito-python/..., sdks/node/..., sdks/python/...
Outcome and lifecycle events expose optional whole-millisecond duration fields, with Node and Python timing tests.
Java context and workflow duration helpers
sdks/java/src/main/java/..., sdks/java/src/test/...
TaskContext, OutcomeEvent, and NodeSnapshot expose duration accessors with null or zero handling for unmeasured timestamps.
Duration API documentation
crates/taskito-core/BINDING_CONTRACT.md, docs/content/docs/...
Documentation describes duration fields, units, examples, and conditions where no runtime is available.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Worker
  participant RustScheduler
  participant JavaBridge
  participant OutcomeEvent
  Worker->>RustScheduler: report result with wall_time_ns
  RustScheduler->>JavaBridge: onOutcome(..., wallTimeNs)
  JavaBridge->>OutcomeEvent: create outcome event
  OutcomeEvent-->>JavaBridge: expose durationMs()
Loading

Possibly related PRs

Suggested reviewers: pratyush618

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The retry-budget-exhausted DLQ metadata change is unrelated to duration reporting and falls outside #483. Move the retry-budget metadata change into a separate PR, or remove it from this changeset, to keep the scope focused on duration reporting.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The requested Java duration accessors are implemented for OutcomeEvent, NodeSnapshot, and TaskContext.
Docstring Coverage ✅ Passed Docstring coverage is 93.88% which is sufficient. The required threshold is 80.00%.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main change: reporting task duration on job outcomes.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/outcome-duration

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@kartikeya-27 kartikeya-27 changed the title Report task duration on job outcomes feat: report task duration on job outcomes Jul 23, 2026
@pratyush618
pratyush618 merged commit 256f7c4 into master Jul 23, 2026
33 of 35 checks passed
@pratyush618
pratyush618 deleted the feat/outcome-duration branch July 23, 2026 06:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Report task duration on Java outcome events and workflow nodes

2 participants