Spark Declarative Pipelines Dagster Integration#33539
Conversation
…rative-pipelines-component
Greptile SummaryThis PR introduces A few non-blocking issues remain:
Confidence Score: 4/5
|
| Filename | Overview |
|---|---|
| python_modules/libraries/dagster-spark/dagster_spark/components/spark_declarative_pipeline/component.py | Core component implementing StateBackedComponent with dataset filtering, path resolution, and multi_asset generation. The silent-fallback issue raised in prior review is now fixed. Minor: ExecutionMode is duplicated from resource.py. |
| python_modules/libraries/dagster-spark/dagster_spark/components/spark_declarative_pipeline/resource.py | subprocess resource leak is fixed with try/finally. ExecutionMode type alias duplicated from component.py. discover_datasets default mode (dry_run_only) differs from component default (dry_run_with_fallback), which may surprise callers. |
| python_modules/libraries/dagster-spark/dagster_spark/components/spark_declarative_pipeline/discovery.py | Comprehensive discovery logic with JSON+text fallbacks, deduplication guard, and source-scanning. _dataset_id_pattern and pattern tuples are recreated on every line in _extract_report_text's outer loop — minor performance issue. |
| python_modules/libraries/dagster-spark/dagster_spark/init.py | SparkPipelinesResource is not re-exported at the package level, making it harder to discover for users who want to configure it in their Dagster projects. |
| python_modules/libraries/dagster-spark/dagster_spark_tests/components/spark_declarative_pipeline/test_resource.py | Good coverage of run_and_observe paths. One assertion assumes dataset string is always the last CLI argument, which breaks if run_extra_args is populated. |
| python_modules/libraries/dagster-spark/dagster_spark_tests/components/spark_declarative_pipeline/test_discovery.py | Thorough tests covering JSON parsing, text fallback, noisy stdout, and duplicate-name detection. No significant issues. |
| python_modules/libraries/dagster-spark/dagster_spark_tests/components/spark_declarative_pipeline/test_component.py | Good lifecycle tests covering sandbox loading, state refresh, temporary view filtering, and override behaviour. No significant issues. |
| python_modules/libraries/dagster-spark/dagster_spark/components/spark_declarative_pipeline/scaffolder.py | Minimal scaffolder that writes a sensible default defs.yaml. No issues. |
| python_modules/libraries/dagster-spark/pyproject.toml | Correct entry-point registration for dg CLI. No issues. |
Sequence Diagram
sequenceDiagram
participant DG as Dagster Daemon
participant Comp as SparkDeclarativePipelineComponent
participant Disc as discover_datasets_fn
participant CLI as spark-pipelines CLI
participant State as StateBackedComponent (fs)
participant Asset as _spark_pipeline_asset
participant Res as SparkPipelinesResource
Note over DG,State: Load / Refresh State Phase
DG->>Comp: refresh_state(working_dir)
Comp->>Disc: discover_datasets_fn(pipeline_spec_path, discovery_mode)
alt dry_run_only / dry_run_with_fallback
Disc->>CLI: spark-pipelines dry-run --spec ...
CLI-->>Disc: JSON or text stdout
Disc->>Disc: parse_dry_run_output_to_datasets()
else fallback / source_only
Disc->>Disc: discover_datasets_from_sources() (regex scan .py/.sql)
end
Disc-->>Comp: list[DiscoveredDataset]
Comp->>State: serialize_value(SparkPipelineState) → state_path
Note over DG,Asset: Build Defs Phase (daemon reload)
DG->>Comp: build_defs_from_state(context, state_path)
Comp->>State: deserialize_value(state_path) → SparkPipelineState
Comp->>Comp: filter temporary_view datasets
Comp->>Comp: build AssetSpecs via get_asset_spec()
Comp-->>DG: Definitions(multi_asset, SparkPipelinesResource)
Note over Asset,CLI: Execution Phase (materialize)
Asset->>Res: run_and_observe(context, pipeline_spec_path, execution_mode, asset_keys)
Res->>CLI: spark-pipelines run --spec ... [--refresh|--full-refresh|--full-refresh-all] [datasets]
loop stdout streaming
CLI-->>Res: log line
Res->>DG: context.log.info(line)
end
CLI-->>Res: returncode
alt returncode != 0
Res-->>Asset: raise SparkPipelinesExecutionError
else success
Res-->>Asset: return
Asset-->>DG: yield MaterializeResult(asset_key) per selected key
end
Reviews (2): Last reviewed commit: "pyright fix" | Re-trigger Greptile
…s/spark_declarative_pipeline/component.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
…s/spark_declarative_pipeline/resource.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
…s/spark_declarative_pipeline/resource.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
…s/spark_declarative_pipeline/resource.py Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
xionon
left a comment
There was a problem hiding this comment.
Overall I think the most important thing here is that we need some kind of verification against an actual pyspark or spark server; an integration test, or a script to replay a dry run that exports some test fixtures.
…://github.com/michalcabir-ui/dagster into feature/spark-declarative-pipelines-component
|
@greptileai can you please update your review? |
cmpadden
left a comment
There was a problem hiding this comment.
Thank you @michalcabir-ui.
Going to land this, and we can figure out if there are any tweaks / subsequent revisions to follow.
Summary & Motivation
This PR introduces the SparkDeclarativePipelineComponent to the dagster-spark library, providing native orchestration and observability for the new Spark Declarative Pipelines (SDP) framework.
Key Features & Architectural Highlights:
Auto-Discovery: Automatically infers datasets (Materialized Views, Streaming Tables) via spark-pipelines dry-run, with a robust, regex-based static source parsing fallback for environments where dry-run is unavailable.
State Management: Implemented as a StateBackedComponent to cache discovered datasets, avoiding JVM overhead during daemon reloads.
Optimized Execution: Uses context.is_subset to intelligently pass explicit dataset keys or utilize the --full-refresh-all flag to avoid OS argument length limits.
Real-time Observability: Streams execution logs directly to Dagster's UI using unbuffered subprocess execution (PYTHONUNBUFFERED=1). Prevents memory leaks on long-running jobs by utilizing a bounded collections.deque for log tailing.
Strict Error Handling: Differentiates between discovery errors and execution failures (SparkPipelinesExecutionError), preventing silent exception swallowing during source parsing.
How I Tested These Changes
Added 22 comprehensive unit tests across test_component.py, test_discovery.py, and test_resource.py.
Verified complex JSON and structured text parsing fallbacks, including deduplication validation.
Tested subprocess execution paths, ensuring accurate log streaming, timeout handling (configured to 60s for daemon safety), and proper exception bubbling.
Validated multi-asset generation, ensuring temporary views are filtered out by default unless explicitly overridden.
Changelog
dagster-spark: Added SparkDeclarativePipelineComponent for orchestrating Spark Declarative Pipelines (SDP).