GeezerVisonThe World Wide Web, restored to 800 pixels of glory. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Home|About|Gaming cabinet|Archives|How it works|Starter sites | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
GeezerVison is showing github.com — [connectors] Make pause take effect more promptly. by blp · Pull Request #7941 · feldera/feldera Conversation
|
| Before | After |
|---|---|
| A paused pipeline processes all buffered input. | A paused pipeline polls only HTTP input endpoints. These accept input while paused only with force=true. Other buffered input waits until resume. |
The server reports Paused at once, while a step can still take input. |
The circuit thread copies the state to reported_state between steps. Steps select their input by reported_state, and the server reports it. A reported pause thus means that no step takes connector input. |
The paused selection is a new StepInputs::Paused variant, so that a coordinator can request it too (second commit). feldera/cloud#2208 uses it so that a paused multihost pipeline processes forced HTTP input.
Exceptions:
has_run), steps poll all endpoints. No reader has buffered input yet, and the first poll records each connector's resume position, which a checkpoint needs.StepInputs::Paused while paused.This is an incompatible change. The docs (testing.md, lifecycle.md, changelog) and the docstring of the SDK's pause() describe the new behavior.
paused_pipeline_does_not_poll_buffered_input, paused_pipeline_polls_until_it_first_runs, paused_pipeline_processes_forced_http_input and multihost_paused_step_polls_only_http_input. Each fails without its change./stats reports the same state as /status.connector_suites for controller::, server::, transport::http and delta_table: all pass, except kafka_server, which needs a Kafka broker.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
@ryzhyk This is a draft only because I am uncertain whether we want to fix this behavior at all, since it is so long-standing. On the other hand, the behavior is always confusing. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
Sounds like a useful feature |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| let state = match global_metrics.get_state() { | ||
| PipelineState::Terminated => PipelineState::Terminated, | ||
| _ => global_metrics.reported_state(), | ||
| }; |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
bug (medium): /status now reports reported_state, but /stats (ExternalGlobalControllerMetrics.state, controller/stats.rs ~L1706) still serializes the requested state. A client that polls pipeline.stats().global_metrics.state == PAUSED sees Paused while a step can still take connector input, so it does not get the guarantee this PR adds, and the two endpoints disagree for up to one step. Suggest serializing reported_state() there too, except for Terminated as here.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Fixed. GlobalControllerMetrics::reported_state() now returns Terminated once the pipeline terminates, and /stats serializes it, as /status does. The two endpoints now use the same rule.
-- Claude Code, replying at @blp's request.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| A paused pipeline does not process the input that its connectors | ||
| buffered, except forced input to HTTP input connectors. When this | ||
| function waits, it returns after the step that was in progress at the | ||
| time of the pause is complete. |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
pitfall (medium): wait_for_idle() returns only when total_input_records == total_processed_records. A paused pipeline now holds buffered input, and the PR says connectors can still buffer for a short time after the pause, so pause(); wait_for_idle() (the pattern in tests/workloads/test_now.py) can now hang until its timeout. Please say this here and in the wait_for_idle docstring and testing.md, or have wait_for_idle compare total_processed + buffered while paused.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Documented in the wait_for_idle docstring and in testing.md. I did not change wait_for_idle to count buffered input while paused: then it would also return early while the pipeline runs with input that is not yet processed, unless it first checked the status, and "idle" would mean different things in the two states.
tests/workloads/test_now.py is not affected: it waits for buffered_input_records == 0 before it pauses, and its datagen input is finite.
-- Claude Code, replying at @blp's request.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Update: on reflection, I changed wait_for_idle after all. It now reads state and buffered_input_records from the same /stats response. For a paused pipeline, it counts buffered input as processed (input == processed + buffered), and it resets the idle interval when the buffered count changes. A running pipeline uses the old rule. /stats now reports the same state as /status, so a reported pause means that no step takes that input. New unit tests: python/tests/unit/test_wait_for_idle.py. The paused case fails with the old rule.
-- Claude Code, replying at @blp's request.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
What I ran (debug,
missing (medium): forced HTTP input while paused. Only + /// A paused pipeline still processes forced HTTP input, and `/status` + /// reports `Paused` throughout. + #[engine_test] + pub fn paused_pipeline_processes_forced_http_input(engine: &dyn PipelineTestEngine) { + actix_web::rt::System::new().block_on(async { + crate::ensure_default_crypto_provider(); + let server = start_test_server( + engine, + &json!({"name": "test", "inputs": {}, "outputs": {}}), + Uuid::new_v4(), + ) + .await; + start_pipeline(&server).await; + send_input(&server, &test_batches(0, 10)).await; + pause_pipeline(&server).await; + let CompletionTokenResponse { token } = + TestHttpSender::send_stream_deserialize_resp::<CompletionTokenResponse>( + server.post("/ingress/test_input1?force=true"), + &test_batches(10, 10), + ) + .await; + wait_for_completion(&server, &token).await; + assert_eq!(get_stats(&server).await.global_metrics.total_processed_records, 20); + wait_for_status(&server, RuntimeStatus::Paused).await; + }) + } Other uncovered cases (medium):
None of these has a test. Gates: tests, flakiness, docs and the breaking-change changelog entry all pass. The two inline comments cover the |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
fb82f18 to
365aa7f
Compare
42413b8 to
2ac9938
Compare
|
Thanks. Changes for the uncovered cases:
The -- Claude Code, replying at @blp's request. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
Before, a paused single-host pipeline continued to poll its input connectors, so input that they buffered before or shortly after the pause still went into the circuit. No API could confirm that input had stopped, which made tests nondeterministic. Now, without a coordinator, a paused step polls only HTTP input endpoints (which accept input while paused only with `force=true`) and, during a checkpoint, the endpoints that block it. The circuit thread records which pause or start it applied, and the pipeline reports `Paused` only after it applies the pause, so no step in progress can take more input. A multihost pipeline already stops at a pause, because its coordinator does not step. For a paused pipeline, the Python SDK's `wait_for_idle()` counts the input that connectors hold in buffers as if it were processed, because the pipeline does not process it until it resumes. Fixes #7568. Signed-off-by: Ben Pfaff <[email protected]>
…teps. A paused single-host pipeline polled only HTTP input endpoints by means of a separate `paused` flag in `StepSelection`, with `inputs` set to `All`. Such a step recorded a `StepFeed` that left out the endpoints that it did not poll, so a transaction commit could take them as drained. Now the selection is `StepInputs::Paused`. It polls only HTTP input endpoints and records no `StepFeed`, as for `CheckpointBarriers`. A coordinator can request the same selection, so that a paused multihost pipeline can process forced HTTP input (feldera/cloud#2208). A pipeline reports the new `paused_step_inputs` capability, because an older pipeline cannot parse a step request with `StepInputs::Paused`. Signed-off-by: Ben Pfaff <[email protected]>
2ac9938 to
bcebd9f
Compare
|
Update on the uncovered cases:
The full local connector run, with Postgres, Redis, DynamoDB and Redpanda, is still in progress. -- Claude Code, replying at @blp's request. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
End-to-end check on a local k3d cluster. A pipeline has a datagen table (200 rows/s) and an HTTP-only table. The script starts it, pauses, waits 5 s, sends 10 rows with
-- Claude Code, replying at @blp's request. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
At least 1 approving review is required to merge this pull request.
There was an error while loading. Please reload this page.
Successfully merging this pull request may close these issues.
[manager] There is no way to check that all input connectors are paused
There was an error while loading. Please reload this page.