pipeline-manager: reduce dependency of platform on the runtime - #6288
Conversation
mihaibudiu
left a comment
There was a problem hiding this comment.
This looks pretty simple
mythical-fred
left a comment
There was a problem hiding this comment.
The direction is clearly right — reducing the manager↔runtime coupling on ProgramSchema is a long-overdue layering fix, and ProgramSchemaPropertiesOnly is a tidy way to peel off only the names+properties the manager actually needs. The two commits split cleanly. Posting COMMENT rather than APPROVE because there are no new tests covering the new manager behavior (parsing only the properties subset, and surviving a runtime schema field the manager doesn't know about) — given how much logic is shifting at the layer boundary, even one round-trip test where the JSON contains an unknown field nested inside fields[].columntype would make me much happier that future schema drift won't silently break.
Inline findings below — all soft, none blocking.
| ConnectorGenerationError::ExpectedInputConnector { position, .. } => position, | ||
| ConnectorGenerationError::ExpectedOutputConnector { position, .. } => position, | ||
| ConnectorGenerationError::RelationConnectorNameCollision { position, .. } => position, | ||
| ConnectorGenerationError::InvalidProgramSchema { .. } => SourcePosition { |
There was a problem hiding this comment.
InvalidProgramSchema reports as SourcePosition { 0, 0, 0, 0 } which renders in compiler errors as line 0:0 — confusing for the user (and looks like a bug). This error isn't tied to user SQL, so consider rendering it without a position, or use None-like sentinel handling upstream so the position is omitted in SqlCompilerMessage.
f4b336e to
cf187f7
Compare
mythical-fred
left a comment
There was a problem hiding this comment.
Thanks for the quick turnaround — cf187f7c07 addresses most of what I raised:
- (1)
Defaultis now removed fromProgramInfo, so theValue::Nullfootgun is gone. - (2)
InvalidProgramSchemanow returns an all-zeroSourcePositionexplicitly. Functional, but readingline 0:0in aSqlCompilerMessagewill still confuse anyone debugging a manager-side parse failure. Nit, not a blocker. - (3) The new
validate_program_infoparses viaProgramSchemaPropertiesOnly::deserialize(&program_schema)(borrow), nice. The deepclone()is still present at thepipeline_diff.rssite though. - (4) Doc wording fixed — clear now.
- (5)
pipeline_diff.rsnow has an explicitTODO: consider parsing only the necessary subset— acknowledging the drift problem isn't solved at the diff site. Fair as a follow-up.
The one thing I still wish were in this PR is a manager-layer roundtrip test: a JSON blob with an extra nested field inside fields[].columntype (or a wholly new top-level field on Relation) that ProgramSchemaPropertiesOnly swallows cleanly while a ProgramSchema parse on the same blob would fail. That's the contract this layering buys us, and without a test it's only true by inspection. Happy to switch to APPROVE once that's covered (or with a tracking issue if you'd rather defer).
|
I assume that merging this will require upgrading the deployed platform, it's not just a question of putting it in the merge queue. |
Once this goes through OSS and cloud CI, the platform will get upgraded automatically |
mythical-fred
left a comment
There was a problem hiding this comment.
LGTM, upgrading to APPROVE.
The two remaining items from my prior COMMENT review are addressed in 65a8830:
ProgramSchemaPropertiesOnlyis now exercised in unit tests insql_compiler.rs::test::compile_basic_program(assertsname+propertiesmatch the fullProgramSchema) and incompile_program_with_connector_properties(asserts the inline-connector properties survive subset parsing). Direct coverage of the manager-layer subset-parse path I asked about \u2014 thanks.generate_pipeline_configis simplified:program_infois no longer threaded through, and thepipeline_diff.rssite has a TODO acknowledging the same compatibility risk for that consumer. Fine as a follow-up.
The new AutomatonCannotConstructProgramInfoUrl early-return when program_info_integrity_checksum is missing is consistent with the new mandatory-program_info_url shape (matches #6294, now merged).
Note: Default derive is gone from ProgramInfo, so callers that previously used ProgramInfo::default() have been removed cleanly in db/test.rs. Good.
65a8830 to
6ba3774
Compare
mythical-fred
left a comment
There was a problem hiding this comment.
Re-approve. Prior concerns addressed: ConfigMap-size workaround in generate_pipeline_config is gone; manager now parses only ProgramSchemaPropertiesOnly in generate_program_info (db/types/program.rs); program_info_url is required end-to-end with a dedicated error variant; sql_compiler.rs adds a roundtrip test that decodes the same payload as both ProgramSchema and ProgramSchemaPropertiesOnly and asserts name+properties match. The deep-clone in pipeline_diff.rs is still there but carries a TODO and is acknowledged as the remaining drift site — fair as a follow-up. LGTM.
|
This failed in CI due to a failure of |
6ba3774 to
299c620
Compare
No, that's a test issue. @abhizer is looking into it. |
|
CI of this PR is failing currently due to: #6320 |
|
Doing early CI run to catch any other test failures: https://github.com/feldera/feldera/actions/runs/26452154977 |
299c620 to
a17c9ec
Compare
|
@snkas I fixed the last failure you have reported, it was in the python SDK. |
|
Fixes #6320 |
|
Can we merge this? |
|
Once downstream CI passes, yes |
- Remove ConfigMap size workaround. We used to store a truncated version of program schema + connector configurations in the ConfigMap. This is only required for pre-v0.199 pipelines, since new pipelines receive this information from the compiler server instead of the ConfigMap. This backward compatibility code is removed, and eliminates the possibility of ConfigMaps growing beyond 1MB and reduces the dependency the platform has on the runtime. - Don't parse relation schema in the manager. Pipeline manager needs to parse program schema in order to validate and name connectors. This introduces an unfortunate dependency between the platform and the runtime and we are hoping to eliminate it by moving connector validation into the compiler. For now, we reduce the surface of the dependency by having the pipeline manager parse only the properties field in each relation, ignoring the SQL schema info. This reduces the likelihood of runtime/platform compatibility issues. - Require `program_info_url` as part of `provision()`. The `program_info_url` is now a mandatory parameter for a pipeline to be able to be started, as its absence has been long enough deprecated. An error is added in case it is missing. This makes it consistent with how program info is handled across runners. Co-authored-by: Leonid Ryzhyk <ryzhyk@gmail.com> Co-authored-by: Mihai Budiu <mbudiu@feldera.com> Signed-off-by: Leonid Ryzhyk <ryzhyk@gmail.com> Signed-off-by: Mihai Budiu <mbudiu@feldera.com> Signed-off-by: Simon Kassing <simon.kassing@feldera.com>
a17c9ec to
2aa51ea
Compare
mythical-fred
left a comment
There was a problem hiding this comment.
Re-review on 2aa51ea7de (force-pushed squash; PR renamed from "Relax pipeline manager → program schema dependency" to "pipeline-manager: reduce dependency of platform on the runtime").
The new commit is much broader than what I last approved at 6ba37743ed. A single squashed commit now bundles at least five logically distinct changes:
RuntimeConfig::datafusion_memory_mb— new config field, 5% default capped at 2 GB, plumbing intocircuit_config(controller.rs:4866) and the DataFusion runtime env (adapterlib/src/utils/datafusion.rs), plusConfigError::DatafusionMemoryExceedsBudgetand an adhoc-sort pool-size warning.BootstrapConfigwrapper (infeldera-types/src/runtime_status.rs) introducing a newsilent_bootstrapflag on the start endpoint, plumbed through the DB column (backward-compatible string parse) and the local runner CLI as--silent-bootstrap.- New
PipelineExecutor::can_provision()trait method called duringStoppedto fail-fast on bad runner config; newRunnerError::RunnerConfigError. runtime_config: &serde_json::Valuethreaded through every trait method (provision,is_provisioned,check,stop,clear), plusdiscover_namespace_from_runtime_config_jsonutility — clearly motivated by the Kubernetes runner needing thenamespacewithout re-deserializingRuntimeConfig(and the new comment onResourceConfig::namespaceasking future PRs not to move/retype that field is good).- State-machine refactor: new
Action::RemainStoppedUpdateErrorreplacing severalTransitionToStoppingpaths inpipeline_automata.rs(unsupported platform version, failed compilation,AutomatonInvalidRuntimeConfig,AutomatonMissingProgramInfo,AutomatonInvalidProgramInfo,AutomatonFailedToSerializeDeploymentConfig).db/test.rsupdated to assert the new semantics (transit_deployment_resources_status_to_stoppednow errors withInvalidResourcesStatusNotRemainfor an already-stopped pipeline; refresh_version stays at 21 instead of bumping to 22).
The headline finding from the original PR — replacing the typed schema with serde_json::Value in ProgramInfo and parsing only ProgramSchemaPropertiesOnly at the connector-generation site — is still here, and the test in sql_compiler.rs for "parse subset, tolerate unknown nested fields" still covers it. The decoupling goal is unchanged from my prior APPROVE.
This is too much for one squash. Reviewers downstream (and git blame readers) cannot easily separate "the platform/runtime decoupling we approved" from "datafusion memory budget split", "silent bootstrap", "can_provision trait extension", and "state-machine refactor". Each of items 1, 2, 3+5 deserves its own PR with its own title/description and its own bisection point if it regresses. Even keeping them as separate commits inside this PR (no squash, with the original titles preserved) would help — the merge-queue squash will still flatten on merge, but review can proceed on isolated diffs. Strongly suggest splitting before merging.
A few concrete concerns within the new scope:
BootstrapConfig::active_bootstrap_policy() (runtime_status.rs:255) panics via expect("bootstrap policy must be set for an active deployment") if the inner bootstrap_policy: Option<BootstrapPolicy> is None. The invariant on the active-deployment path should hold: pipeline_management.rs always constructs the value with bootstrap_policy: Some(..), and parse_string_as_bootstrap_config for the legacy string formats produces Some too. But pipeline_automata.rs:1319 constructs it via Some(pipeline.bootstrap_policy.unwrap_or_default()), and the Default for BootstrapConfig is bootstrap_policy: None, silent_bootstrap: false — i.e. invalid for any consumer of active_bootstrap_policy(). If pipeline.bootstrap_policy is ever None here (e.g. a stored row that hasn't been written yet, or a future code path that forgets to set it), the local runner will panic at local_runner.rs:600 rather than fail-stop the pipeline with a clear error. Two reasonable fixes: drop Default from BootstrapConfig and use pipeline.bootstrap_policy.expect(..) so the panic point is explicit, or make the inner bootstrap_policy non-optional and default to BootstrapPolicy::default(). Today's shape is a footgun.
datafusion_memory_mb defaults. The 5% / 2 GB ceiling is sensible for typical pipelines, but resolved_datafusion_memory_mb does plain integer arithmetic effective * 5 / 100. For tiny budgets (say max_rss_mb: Some(10)) you get 0 MB; controller.rs then accepts it (0 < 10) and DataFusion is built with FairSpillPool::new(0). Worth a small floor so a misconfigured tiny budget gives a clearer error than first-allocation ResourcesExhausted. Non-blocking, but the docstring already calls out that under-sized pools surface as ResourcesExhausted — bound the obvious zero case at construction.
python/feldera/_helpers.py. Defaulting an unknown column shape to "struct" silently is a future bug magnet:
if "type" in column["columntype"]:
column_type = column["columntype"]["type"]
else:
# default column type
column_type = "struct"
If a new top-level column-type shape lands in the schema, every Python client will silently treat it as a struct and likely produce wrong rows. At minimum log a warning; better, raise on unknown shape and require explicit handling.
pipeline_diff.rs still deep-clones the program schema on every diff (the TODO from my original review). Not regressed, just unchanged; acceptable as follow-up.
Net: the decoupling work is good and the can_provision + state-machine refactor are sensible improvements, but I'd like to see this split. If splitting is genuinely off the table, please at least (a) fix the active_bootstrap_policy() invariant so we cannot construct an invalid BootstrapConfig and then panic later, and (b) update the PR description to enumerate the five themes so future archaeology has a chance.
Remove ConfigMap size workaround.
We used to store a truncated version of program schema + connector configurations in the ConfigMap. This is only required for pre-v0.199 pipelines, since new pipelines receive this information from the compiler server instead of the ConfigMap. This backward compatibility code is removed, and eliminates the possibility of ConfigMaps growing beyond 1MB and reduces the dependency the platform has on the runtime.
Don't parse relation schema in the manager.
Pipeline manager needs to parse program schema in order to validate and name connectors. This introduces an unfortunate dependency between the platform and the runtime and we are hoping to eliminate it by moving connector validation into the compiler. For now, we reduce the surface of the dependency by having the pipeline manager parse only the properties field in each relation, ignoring the SQL schema info. This reduces the likelihood of runtime/platform compatibility issues.
Require
program_info_urlas part ofprovision().The
program_info_urlis now a mandatory parameter for a pipeline to be able to be started, as its absence has been long enough deprecated. An error is added in case it is missing. This makes it consistent with how program info is handled across runners.PR information