viirya commented on PR #54:
URL: 
https://github.com/apache/spark-connect-rust/pull/54#issuecomment-5420369794

   Third pass. My open item is fixed and it paid off immediately. I ran the 
suite this round rather than only reading it — 329 tests pass, 0 failures on 
the default (server-free) members. One residual robustness item at the end; 
nothing I'd consider blocking.
   
   ## The e2e-in-CI fix landed, and found a bug within one commit
   
   `SPARK_REMOTE: sc://localhost:15002` is now set in the `connect-parity` job 
(`build_python_connect.yml:180`), reusing the Spark 4.2.0 server already 
standing up there and running five e2e targets with `--test-threads=1` since 
they share a session. Reusing the existing server rather than adding a job is 
the right call, and the comment explains why the step exists.
   
   The payoff is `3559267`: with those assertions actually executing, 
`e2e_coverage::catalog_surface` caught that the catalog list ops (`listTables`, 
`listColumns`, `getDatabase`, …) eagerly executed and then (a) errored with 
"Catalog operation returned no rows" whenever the result was *legitimately* 
empty — `listTables` on a database with no tables — and (b) rebuilt the 
DataFrame as a `LocalRelation` with `data: None`, discarding the real rows and 
coercing every column to String.
   
   The fix is the right shape: represent the op as a relation 
(`LogicalPlan::Catalog` → `RelType::Catalog`) and return it lazily, so the 
server's actual schema and rows flow through `.collect()`. That fixes the empty 
case and the schema/data loss together, rather than special-casing the empty 
result. `RelType::Catalog` is already covered by `catalog_golden.rs`, so the 
new plan variant isn't untested.
   
   ## Restoring the server-free net was a good catch I'd missed
   
   `plan_serialization.rs` is an unprompted addition, and it closes a gap my 
own review opened: swapping the assertion-free `*_coverage_golden.rs` snapshots 
for live-server behavioral tests removed the coverage that ran *without* a 
server. The new file puts that back — 6 assertions, zero server gates, so it 
runs in the server-less job — and covers all seven `JoinType` variants mapped 
to their proto enums, including `RightOuter`/`FullOuter`/`LeftSemi`/`LeftAnti`. 
Those are exactly the ones where an off-by-one in an enum mapping produces 
silently wrong joins rather than an error, so pinning them server-free is worth 
more than the line count suggests.
   
   ## Also confirmed
   
   - **Golden set extended 440 → 508** byte-for-byte against the reference 
client, after re-capturing (518 available vs the stale 440).
   - **`uuid` and `tuple_sketch_agg_{double,integer}`** now materialize the 
trailing default args the reference emits, so they rejoin the byte-for-byte set 
instead of being excluded. `count_min_sketch` joins the random-seed 
normalization.
   - **`DataFrameWriterV2.option`/`options`** now route through 
`coerce_option_value` like the V1 writer, so `writeTo(...).options(x=None)` no 
longer sends the string `"None"` and `option(k, True)` no longer sends `"True"`.
   - **`types_behavior.rs`** has no server gate, so its 55 assertions run 
unconditionally in the server-less job — which was the smaller note from my 
last comment.
   
   ## Residual: the silent-pass guard is now a latent trap rather than a live 
bug
   
   The CI wiring is correct, so the coverage is real today. But the guard shape 
that caused the original problem is unchanged:
   
   ```rust
   fn should_run() -> bool { std::env::var("SPARK_REMOTE").is_ok() }
   ...
   if !should_run() { return; }
   ```
   
   I checked what that reports with no server configured:
   
   ```
   $ cargo test -p apache-spark-connect --test e2e_functions
   running 3 tests
   test result: ok. 3 passed; 0 failed ... finished in 0.00s
   ```
   
   Three tests report **passed** in 0.00 s while asserting nothing.
   
   Today that's harmless because the CI step exists. The concern is that 
nothing detects it silently going away: if the step is renamed or reordered, or 
the server fails to come up and the step's failure is tolerated, these tests 
revert to reporting green while checking nothing — and the only signal would be 
a bug like the catalog one shipping unnoticed. Given the whole point of these 
tests is catching silently-wrong values, a guard that fails silently is an 
unfortunate pairing.
   
   Cheapest fix I can see: have `should_run()` panic (or `assert!`) when a 
`REQUIRE_SPARK_REMOTE=1` env var is set, and export that in the CI step. A 
missing server then fails loudly exactly where it matters, while local `cargo 
test` keeps skipping freely. `#[ignore]` would also make the skip visible 
rather than a pass, though it changes how you invoke them locally.
   
   ## New: an unreachable server makes the e2e tests hang for ~13 minutes, not 
fail
   
   I went looking for the other half of the guard behaviour — what happens when 
`SPARK_REMOTE` *is* set but nothing is listening — and it isn't a quick failure:
   
   ```
   $ SPARK_REMOTE=sc://127.0.0.1:59999 cargo test -p apache-spark-connect 
--test e2e_functions
   running 3 tests
   test aggregate_functions has been running for over 60 seconds
   test conditional_and_collection_functions has been running for over 60 
seconds
   test math_and_string_functions has been running for over 60 seconds
   ```
   
   They were still running when I gave up at four minutes. The cause is the 
retry wiring this PR adds, working as designed: a refused connection surfaces 
as `UNAVAILABLE`, `RetryPolicy::can_retry` treats that as retryable, and 
`with_retry` (which `analyze_plan` and `execute_plan_reattachable` both go 
through) then burns the default budget — `max_retries: 15`, 
`initial_backoff_ms: 1000`, `backoff_multiplier: 2.0`, `max_backoff_ms: 64000`. 
That's ~10.7 min of backoff plus 16 × the 10 s `READY_TIMEOUT`, so roughly **13 
minutes per operation** before the error surfaces.
   
   This isn't a defect in the retry policy — it mirrors the reference client, 
and for a genuinely flaky server it is the behaviour you want. But it interacts 
badly with the new CI step in a specific way: if the Spark server fails to come 
up in `connect-parity`, the e2e step won't fail fast with "connection refused"; 
it will sit there retrying until the job or step timeout kills it, and the log 
will show tests "running for over 60 seconds" rather than the actual cause. 
Worth either capping retries for the e2e step (an env override, or a shorter 
policy when `SPARK_REMOTE` is explicitly set) or making sure that step carries 
a timeout tight enough to fail with a legible message. Same consideration 
applies to anyone running these locally against a server that isn't up — the 
13-minute hang reads as a broken test rather than a missing server.
   
   ## What I verified
   
   I ran `cargo test` on the default members (329 passed, 0 failed), and ran 
`e2e_functions` both without `SPARK_REMOTE` (3 tests report passed in 0.00 s) 
and with it pointed at a closed port (hangs past four minutes; the ~13 min 
figure is computed from the default `RetryPolicy` constants, not measured to 
completion). I did not run the parity gate, the coverage script, or the e2e 
tests against a live server, so the claims about the catalog fix and the 
38-test e2e suite passing against 4.2.0 I'm taking from the commit messages.
   


-- 
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