Surface per-task status summary in Helix JobContext - #214
Surface per-task status summary in Helix JobContext#214LZD-PratyushBhatt wants to merge 3 commits into
Conversation
When a Task Framework job is configured with a high FailureThreshold so that every partition task is allowed to run to completion, the job's own status flag stays COMPLETED even if individual tasks fail. That masks partial failures: operators watching only the job state cannot tell that some partitions errored, aborted, or timed out. This adds an aggregated, job-level task status summary that the controller computes and writes into the JobContext when a job reaches a terminal state (completed, failed, or timed out). The summary carries completed/failed counts, a per-state breakdown, and the list of failed partitions, so partial failures stay visible even when the job flag is COMPLETED. Reading the summary is a clean alternative to the Integer.MAX_VALUE FailureThreshold workaround. helix-core: - JobContext#updateTaskStatusSummary computes the summary from per-partition states and stores it as the TASK_STATUS_SUMMARY simple field (JSON); JobContext#getTaskStatusSummary reads it back. - AbstractTaskDispatcher invokes it at the three terminal choke points (markJobComplete, failJob, handleJobTimeout). helix-front: - Job detail view gains a "Task Summary" tab that parses TASK_STATUS_SUMMARY and highlights failures. Tests: - TestJobTaskStatusSummary integration test (job COMPLETED, summary reports the failures). - JobTaskSummaryDriver standalone end-to-end driver (runs against a live ZK). - job-detail component specs for the new getters. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
7edef10 to
5d3303d
Compare
| for (int p : partitions) { | ||
| TaskPartitionState state = getPartitionState(p); | ||
| String key = (state == null) ? "UNSCHEDULED" : state.name(); | ||
| byState.merge(key, 1, Integer::sum); |
There was a problem hiding this comment.
good one, byState is just the raw per-state histogram behind the coarse counts. each TaskPartitionState name (plus UNSCHEDULED when a partition has no state yet) maps to how many tasks are in that state. added a javadoc para on updateTaskStatusSummary() spelling it out.
| failedTasks.sort(null); | ||
|
|
||
| Map<String, Object> summary = new LinkedHashMap<>(); | ||
| summary.put("total", partitions.size()); |
There was a problem hiding this comment.
I'd recommend using string constants instead of hard coding these keys in the map
There was a problem hiding this comment.
yeah makes sense. pulled all the summary keys (total, completed, failed, timedOut and the Tasks arrays) plus UNSCHEDULED into named SUMMARY_KEY_ and SUMMARY_STATE_UNSCHEDULED constants, and the map builds off those now instead of inline literals.
|
|
||
| Workflow flow = | ||
| WorkflowGenerator.generateSingleJobWorkflowBuilder(jobResource, jobBuilder).build(); | ||
| System.out.println("Submitting workflow '" + jobResource + "' with " + NUM_TASKS |
There was a problem hiding this comment.
do we know need these print statements in tests anymore?
There was a problem hiding this comment.
nice catch, not needed. that was a standalone main() driver, not a TestNG test, and it needed an external ZK plus it just duplicated TestJobTaskStatusSummary. dropped the whole file so the prints go with it. coverage stays via that integration test plus a new deterministic TestJobContextTaskStatusSummary unit test.
sjainit
left a comment
There was a problem hiding this comment.
Just wondering, do we also have workflow level summary like we are aggregating at job level ?
Reviewer feedback on the per-task status summary asked to also surface in-progress and timed-out tasks as first-class counts, rather than having timed-out tasks folded into the failed count and in-progress tasks hidden inside "other". helix-core: - JobContext#updateTaskStatusSummary now emits explicit "timedOut" and "inProgress" counts plus "timedOutTasks" and "inProgressTasks" partition lists. The top-level counts partition the tasks as total = completed + failed + inProgress + other; timedOut is called out as the subset of failed that timed out, and inProgress (INIT or RUNNING) is pulled out of "other" so still-running tasks are visible when the summary is written at the job-timeout choke point. - failed and failedTasks keep their existing meaning (a timed-out task is still counted as failed), so existing consumers are unaffected. helix-front: - Job detail Task Summary tab shows Timed Out and In Progress chips and the corresponding partition lists, and flags timed-out tasks as a problem. Tests: - Integration test asserts the new counts are present and that the top-level counts partition the total. - Standalone driver verifies the timedOut and inProgress keys are always emitted. - Job detail component spec covers the new getters and a scenario with timed-out and in-progress tasks. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ew feedback - Split INIT tasks into a separate "pending" bucket, distinct from "inProgress" (RUNNING), in the JobContext task status summary. - Recompute the summary on the job detail page from per-partition states each time the page is opened, falling back to the stored terminal snapshot when needed. - Extract the summary JSON field names into named SUMMARY_KEY_* constants instead of inline string literals. - Document what the byState histogram represents in updateTaskStatusSummary(). - Remove the standalone JobTaskSummaryDriver; the TestNG integration test and a new deterministic JobContext unit test already cover the same scenario. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
hmmm not yet, this aggregates at the job level only. WorkflowContext already tracks per-job states via getJobStates() so a workflow-level roll-up is very doable, but I think we should keep this PR job-scoped and do the workflow-level one as a follow-up so it gets its own UI and tests. can pick it up next. |
When a Task Framework job is configured with a high FailureThreshold so that every partition task is allowed to run to completion, the job's own status flag stays COMPLETED even if individual tasks fail. That masks partial failures: operators watching only the job state cannot tell that some partitions errored, aborted, or timed out.
This adds an aggregated, job-level task status summary that the controller computes and writes into the JobContext when a job reaches a terminal state (completed, failed, or timed out). The summary carries completed/failed counts, a per-state breakdown, and the list of failed partitions, so partial failures stay visible even when the job flag is COMPLETED. Reading the summary is a clean alternative to the Integer.MAX_VALUE FailureThreshold workaround.
helix-core:
helix-front:
Tests:
Locally tested in real helix cluster:

Issues
(#200 - Link your issue number here: You can write "Fixes #XXX". Please use the proper keyword so that the issue gets closed automatically. See https://docs.github.com/en/github/managing-your-work-on-github/linking-a-pull-request-to-an-issue
Any of the following keywords can be used: close, closes, closed, fix, fixes, fixed, resolve, resolves, resolved)
Description
(Write a concise description including what, why, how)
Tests
(List the names of added unit/integration tests)
(If CI test fails due to known issue, please specify the issue and test PR locally. Then copy & paste the result of "mvn test" to here.)
Changes that Break Backward Compatibility (Optional)
(Consider including all behavior changes for public methods or API. Also include these changes in merge description so that other developers are aware of these changes. This allows them to make relevant code changes in feature branches accounting for the new method/API behavior.)
Documentation (Optional)
(Link the GitHub wiki you added)
Commits
Code Quality
(helix-style-intellij.xml if IntelliJ IDE is used)