Skip to content

Commit ccd72c6

Browse files
authored
Feat: Add a janitor configuration that allows to warn instead of failing if it fails to delete an expired environment schema / view (#4150)
1 parent 73c6ad7 commit ccd72c6

6 files changed

Lines changed: 76 additions & 6 deletions

File tree

docs/reference/configuration.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,16 @@ Formatting settings for the `sqlmesh format` command and UI.
104104
| `append_newline` | Whether to append a newline to the end of the file (Default: False) | boolean | N |
105105
| `no_rewrite_casts` | Preserve the existing casts, without rewriting them to use the :: syntax. (Default: False) | boolean | N |
106106

107+
108+
## Janitor
109+
110+
Configuration for the `sqlmesh janitor` command.
111+
112+
| Option | Description | Type | Required |
113+
|--------------------------|----------------------------------------------------------------------------------------------------------------------------|:-------:|:--------:|
114+
| `warn_on_delete_failure` | Whether to warn instead of erroring if the janitor fails to delete the expired environment schema / views (Default: False) | boolean | N |
115+
116+
107117
## UI
108118

109119
SQLMesh UI settings.

sqlmesh/core/config/janitor.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
from __future__ import annotations
2+
3+
import typing as t
4+
5+
from sqlmesh.core.config.base import BaseConfig
6+
7+
8+
class JanitorConfig(BaseConfig):
9+
"""The configuration for the janitor.
10+
11+
Args:
12+
warn_on_delete_failure: Whether to warn instead of erroring if the janitor fails to delete the expired environment schema / views.
13+
"""
14+
15+
warn_on_delete_failure: bool = False

sqlmesh/core/config/root.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
from sqlmesh.core.config.feature_flag import FeatureFlag
2626
from sqlmesh.core.config.format import FormatConfig
2727
from sqlmesh.core.config.gateway import GatewayConfig
28+
from sqlmesh.core.config.janitor import JanitorConfig
2829
from sqlmesh.core.config.migration import MigrationConfig
2930
from sqlmesh.core.config.model import ModelDefaultsConfig
3031
from sqlmesh.core.config.naming import NameInferenceConfig as NameInferenceConfig
@@ -128,6 +129,7 @@ class Config(BaseConfig):
128129
before_all: t.Optional[t.List[str]] = None
129130
after_all: t.Optional[t.List[str]] = None
130131
linter: LinterConfig = LinterConfig()
132+
janitor: JanitorConfig = JanitorConfig()
131133

132134
_FIELD_UPDATE_STRATEGY: t.ClassVar[t.Dict[str, UpdateStrategy]] = {
133135
"gateways": UpdateStrategy.NESTED_UPDATE,

sqlmesh/core/context.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2292,6 +2292,7 @@ def _cleanup_environments(self) -> None:
22922292
default_adapter=self.engine_adapter,
22932293
engine_adapters=self.engine_adapters,
22942294
environments=expired_environments,
2295+
warn_on_delete_failure=self.config.janitor.warn_on_delete_failure,
22952296
console=self.console,
22962297
)
22972298

sqlmesh/core/state_sync/common.py

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ def cleanup_expired_views(
2626
default_adapter: EngineAdapter,
2727
engine_adapters: t.Dict[str, EngineAdapter],
2828
environments: t.List[Environment],
29+
warn_on_delete_failure: bool = False,
2930
console: t.Optional[Console] = None,
3031
) -> None:
3132
expired_schema_environments = [
@@ -66,9 +67,11 @@ def get_adapter(gateway_managed: bool, gateway: t.Optional[str] = None) -> Engin
6667
if console:
6768
console.update_cleanup_progress(schema.sql(dialect=engine_adapter.dialect))
6869
except Exception as e:
69-
raise SQLMeshError(
70-
f"Failed to drop the expired environment schema '{schema}': {e}"
71-
) from e
70+
message = f"Failed to drop the expired environment schema '{schema}': {e}"
71+
if warn_on_delete_failure:
72+
logger.warning(message)
73+
else:
74+
raise SQLMeshError(message) from e
7275

7376
# Drop the views for the expired environments
7477
for engine_adapter, expired_view in {
@@ -87,9 +90,11 @@ def get_adapter(gateway_managed: bool, gateway: t.Optional[str] = None) -> Engin
8790
if console:
8891
console.update_cleanup_progress(expired_view)
8992
except Exception as e:
90-
raise SQLMeshError(
91-
f"Failed to drop the expired environment view '{expired_view}': {e}"
92-
) from e
93+
message = f"Failed to drop the expired environment view '{expired_view}': {e}"
94+
if warn_on_delete_failure:
95+
logger.warning(message)
96+
else:
97+
raise SQLMeshError(message) from e
9398

9499

95100
def transactional() -> t.Callable[[t.Callable], t.Callable]:

tests/core/state_sync/test_state_sync.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2651,6 +2651,43 @@ def test_cleanup_expired_views(
26512651
]
26522652

26532653

2654+
@pytest.mark.parametrize(
2655+
"suffix_target", [EnvironmentSuffixTarget.SCHEMA, EnvironmentSuffixTarget.TABLE]
2656+
)
2657+
def test_cleanup_expired_environment_schema_warn_on_delete_failure(
2658+
mocker: MockerFixture, make_snapshot: t.Callable, suffix_target: EnvironmentSuffixTarget
2659+
):
2660+
adapter = mocker.MagicMock()
2661+
adapter.dialect = None
2662+
adapter.drop_schema.side_effect = Exception("Failed to drop the schema")
2663+
adapter.drop_view.side_effect = Exception("Failed to drop the view")
2664+
2665+
snapshot = make_snapshot(
2666+
SqlModel(name="test_catalog.test_schema.test_model", query=parse_one("select 1, ds"))
2667+
)
2668+
snapshot.categorize_as(SnapshotChangeCategory.BREAKING)
2669+
schema_environment = Environment(
2670+
name="test_environment",
2671+
suffix_target=suffix_target,
2672+
snapshots=[snapshot.table_info],
2673+
start_at="2022-01-01",
2674+
end_at="2022-01-01",
2675+
plan_id="test_plan_id",
2676+
previous_plan_id="test_plan_id",
2677+
catalog_name_override="catalog_override",
2678+
)
2679+
2680+
with pytest.raises(SQLMeshError, match="Failed to drop the expired environment .*"):
2681+
cleanup_expired_views(adapter, {}, [schema_environment], warn_on_delete_failure=False)
2682+
2683+
cleanup_expired_views(adapter, {}, [schema_environment], warn_on_delete_failure=True)
2684+
2685+
if suffix_target == EnvironmentSuffixTarget.SCHEMA:
2686+
assert adapter.drop_schema.called
2687+
else:
2688+
assert adapter.drop_view.called
2689+
2690+
26542691
def test_max_interval_end_per_model(
26552692
state_sync: EngineAdapterStateSync, make_snapshot: t.Callable
26562693
) -> None:

0 commit comments

Comments
 (0)