feat(janitor): add scoped snapshot cleanup for invalidated environments - #5856
feat(janitor): add scoped snapshot cleanup for invalidated environments#5856mday-io wants to merge 12 commits into
Conversation
In dbt 1.6/1.7 CI environments, snowflake-connector-python resolves to versions 3.0-3.7.x which require pyOpenSSL<24.0.0. When combined with cryptography>=42.0 (which removed the lib.GEN_EMAIL constant), importing the Snowflake connector raises AttributeError: module 'lib' has no attribute 'GEN_EMAIL', failing these tests: - test_snowflake_config (via SnowflakeConnectionConfig._validate_authenticator) - test_api_class_loading[snowflake] (via SnowflakeConfig.relation_class) pyOpenSSL>=24.0.0 forces pip/uv to resolve snowflake-connector-python to 3.8.0+ (which allows pyOpenSSL<25.0.0, thus including 24.x). pyOpenSSL 24.0.0 fixed the GEN_EMAIL incompatibility with cryptography>=42.0. dbt 1.3-1.5 and 1.8-1.10 are unaffected: earlier versions resolve connector packages that avoid this code path; later versions of the connector already widened cryptography's upper bound. Also collapses a multi-line docstring in classproperty to a single line. Signed-off-by: mday-io <mdaytn@gmail.com>
…eanup Adds a `--cleanup-snapshots` flag to `sqlmesh invalidate` that immediately deletes physical snapshot tables exclusively owned by the target environment, without affecting snapshots shared with other environments (e.g. prod). Previously, users had to run `sqlmesh janitor --ignore-ttl` separately after invalidating, which performed a global cleanup across all environments. The new flag provides a scoped alternative that: 1. Captures the environment's snapshot IDs before invalidation 2. Filters to only those not referenced by any other active environment 3. Drops the physical tables and removes the state records for those snapshots Changes: - cli/main.py: add --cleanup-snapshots flag to the invalidate command - core/context.py: pass cleanup_snapshots through to invalidate_environment - core/janitor.py: add delete_snapshots_for_environment() helper function - core/state_sync/base.py: add target_snapshot_ids param to get/delete_expired_snapshots - core/state_sync/db/facade.py: thread target_snapshot_ids through facade - core/state_sync/db/snapshot.py: filter expired query by target_snapshot_ids when provided - core/state_sync/cache.py: add target_snapshot_ids param to CachingStateSync Closes SQLMesh#5844 Signed-off-by: mday-io <mdaytn@gmail.com>
- C1/M4: eliminate TOCTOU race in delete_snapshots_for_environment by calling state_sync.delete_snapshots(batch.expired_snapshot_ids) directly instead of re-querying via delete_expired_snapshots, so physical drops and state removal operate on the same snapshot ID set - M1: remove always-truthy `if target_conditions:` guard in get_expired_snapshots (snapshot_id_filter always yields >= 1 condition) - M2: when cleanup_snapshots=True and the environment does not exist, log a warning and return early instead of printing a misleading success message - m1: unconditionally initialize target_snapshot_ids before the cleanup_snapshots block to prevent potential UnboundLocalError - n1: enforce `sync = sync or cleanup_snapshots` explicitly so the implication is in code, not just docs; update docstring and CLI help to say "cleanup runs synchronously" instead of "Implies --sync" Signed-off-by: mday-io <mdaytn@gmail.com>
ae27f17 to
5c9d308
Compare
Signed-off-by: mday-io <mdaytn@gmail.com>
Signed-off-by: mday-io <mdaytn@gmail.com>
|
@mday-io Might be a good follow-up: GitHub CICD bot ( |
|
@mday-io following up on my prev comment, when you come back from your vacation! |
Signed-off-by: mday-io <mdaytn@gmail.com>
Signed-off-by: mday-io <mdaytn@gmail.com>
|
@StuffbyYuki so I explored setting "cleanup_snapshots=True" after every PR deploy but that would override the TTL behavior for snapshots (1 week). I meant to include this as a "clean the house" option for any stale snapshot issues - like ones I've had personally. |
|
@mday-io Great! Just one leftover nit: docs/reference/cli.md still has a stray “Has” in the --ignore-ttl help (“Has When --environment…”). Refer to my pending review above... |
|
@mday-io Following up one last time! Or I could also make that small change I suppose |
Summary
Closes #5844
Adds scoped snapshot cleanup for invalidated environments.
sqlmesh invalidate --cleanup-snapshotsnow invalidates the target environment and then runs scoped janitor cleanup for only unreferenced snapshots formerly referenced by that environment. This avoids the previous workaround of runningsqlmesh janitor --ignore-ttl, which performs project-wide cleanup of all unreferenced snapshots.The change also makes the scoped cleanup behavior available directly through:
This is particularly useful for CI/CD workflows where PR environments are frequently created and invalidated, but cleanup should not remove unrelated unreferenced snapshots from other invalidated environments.
How it works
get_expired_snapshots(..., target_snapshot_ids=...)to restrict candidate snapshots to that captured set.prod.SnapshotEvaluator.cleanup().Examples
Checklist
make styleand fixed any issuesmake fast-test)git commit -s) per the DCOAdditional validation
pytest tests/core/state_sync/test_state_sync.py -q— 92 passedpytest tests/core/integration/test_aux_commands.py -q— 13 passed