andygrove opened a new pull request, #2026:
URL: https://github.com/apache/datafusion-ballista/pull/2026

   # Which issue does this PR close?
   
   Closes #ISSUE_HARNESS.
   
   This harness reproduces the following, each of which is filed separately:
   
   - #ISSUE_FETCH — shuffle-fetch failures lose their type, so the map-stage 
resubmit never fires
   - #ISSUE_RETRY — retryable IO errors are misclassified when wrapped in 
`DataFusionError::Shared`
   - #ISSUE_HANG — killing every executor hangs the job instead of failing it
   
   # Rationale for this change
   
   Ballista has a substantial high-availability state machine in
   `ballista/scheduler/src/state/execution_graph.rs` (`update_task_status`): 
failures are classified
   `retryable` / `count_to_failures`, tasks retry up to `task_max_failures`, a 
`FetchPartitionError`
   rolls back the running stage and resubmits the map stage, and a lost 
executor resets its running
   tasks and removes the shuffle output it produced so map stages re-run.
   
   None of it was tested end to end. Every existing test of these paths 
fabricates `TaskStatus`
   protobuf messages by hand (`execution_graph.rs` tests, 
`scheduler/src/test_utils.rs`). No test ever
   drove the HA state machine from a real query on a real cluster, and no test 
ever killed an executor.
   
   Running the state machine for real immediately surfaced three bugs, two of 
which mean Ballista
   **fails queries that it is designed to recover from**. See the linked issues.
   
   There is an existing chaos operator (`ChaosExec`), but it is unusable as a 
regression harness: it is
   wired only into the AQE planner (`state/aqe/planner.rs`), so it cannot 
inject faults with AQE off; it
   wraps a *randomly chosen* plan node; and it fires *probabilistically*. No 
test uses the
   `ballista.testing.chaos_execution.*` keys today.
   
   # What changes are included in this PR?
   
   A new non-published workspace crate, `chaos-testing` (`ballista-chaos`). 
**No production crate is
   modified** — the only change outside `chaos-testing/` is adding the member 
to the workspace
   `Cargo.toml`.
   
   - **Fault injection via UDFs, not the planner.** `chaos_fail(guard, mode, 
budget_dir)` and
     `chaos_delay(guard, ms)` are pass-through scalar UDFs spliced into the 
query text, so the identical
     injection works with AQE on and AQE off with zero planner wiring. `mode` 
selects which of Ballista's
     three failure classifications is exercised: `io` (retryable), `exec` 
(non-retryable), `panic`
     (caught by the executor's `catch_unwind`, non-retryable).
   - **Determinism without RNG.** The `guard` predicate over fixed data selects 
*which* partitions fault;
     a filesystem **token budget** bounds *how many* attempts fault, 
cluster-wide, across task retries and
     executor restarts (consuming a token is `fs::remove_file`, which is atomic 
across processes). Budget 1
     means exactly one attempt faults anywhere, so a retry *must* succeed; 
budget ≫ `task_max_failures`
     means retries *must* exhaust.
   - **A real multi-process cluster.** `TestCluster` spawns real 
`chaos-scheduler` / `chaos-executor`
     binaries as OS processes (they inject the UDFs via the existing 
`override_function_registry` /
     `override_session_builder` hooks, following 
`examples/custom-executor.rs`), so executors can be
     `SIGKILL`ed and restarted. It tunes `executor_timeout_seconds` / heartbeat 
down from the production
     defaults of 180s/60s, without which a killed executor would not be noticed 
for three minutes.
   - **Kills land at a known point.** The scheduler's REST API is polled 
(`/api/job/{id}/stages`) so a kill
     happens while a stage genuinely has running tasks, rather than after a 
guessed `sleep`.
   - **Seven scenarios, each run under both AQE settings**: retryable fault 
recovered; retries exhausted;
     panicking task; executor killed mid-stage; executor killed after writing 
shuffle output; executor
     killed and restarted; every executor killed.
   
   The load-bearing assertion in every recovery scenario is **result equality 
against a chaos-free baseline
   run**, not merely "it did not error" — re-running a stage is exactly where 
duplicated or dropped
   partitions would appear, and only a correctness check catches that.
   
   # Current test status
   
   `cargo test -p ballista-chaos -- --test-threads=1` → **11 passed, 5 failed, 
0 ignored.**
   
   The 5 failures are the three bugs above, reproduced end to end. They are 
**left failing on purpose** and
   are not suppressed: a scenario that fails because Ballista is broken is the 
point of this harness. Each
   is documented in `chaos-testing/README.md` with its root cause. Once the 
linked issues are fixed, these
   scenarios become the regression tests for them.
   
   Passing: baseline correctness (both AQE settings), retry-on-IO-fault with 
AQE off, retry exhaustion,
   panicking task (job fails cleanly, executor survives), executor killed after 
shuffle write, and
   executor kill + restart.
   
   # Are there any user-facing changes?
   
   No. The crate is test-only and `publish = false`; no production crate is 
touched.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to