Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Support a dynamic minimum interval for alerts and reports #29241

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions docs/docs/configuration/alerts-reports.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,17 @@ ALERT_MINIMUM_INTERVAL = int(timedelta(minutes=10).total_seconds())
REPORT_MINIMUM_INTERVAL = int(timedelta(minutes=5).total_seconds())
```

Alternatively, you can assign a function to `ALERT_MINIMUM_INTERVAL` and/or `REPORT_MINIMUM_INTERVAL`. This is useful to dynamically retrieve a value as needed:

``` python
def alert_dynamic_minimal_interval(**kwargs) -> int:
"""
Define logic here to retrieve the value dynamically
"""

ALERT_MINIMUM_INTERVAL = alert_dynamic_minimal_interval
```

## Custom Dockerfile

If you're running the dev version of a released Superset image, like `apache/superset:3.1.0-dev`, you should be set with the above.
Expand Down
2 changes: 2 additions & 0 deletions superset/commands/report/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ def validate_report_frequency(
else "REPORT_MINIMUM_INTERVAL"
)
minimum_interval = current_app.config.get(config_key, 0)
if callable(minimum_interval):
minimum_interval = minimum_interval()

if not isinstance(minimum_interval, int):
logger.error(
Expand Down
1 change: 1 addition & 0 deletions superset/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -1375,6 +1375,7 @@ def EMAIL_HEADER_MUTATOR( # pylint: disable=invalid-name,unused-argument
ALERT_REPORTS_MAX_CUSTOM_SCREENSHOT_WIDTH = 2400
# Set a minimum interval threshold between executions (for each Alert/Report)
# Value should be an integer i.e. int(timedelta(minutes=5).total_seconds())
# You can also assign a function to the config that returns the expected integer
ALERT_MINIMUM_INTERVAL = int(timedelta(minutes=0).total_seconds())
REPORT_MINIMUM_INTERVAL = int(timedelta(minutes=0).total_seconds())

Expand Down
46 changes: 44 additions & 2 deletions tests/unit_tests/commands/report/base_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,17 @@
TEST_SCHEDULES = TEST_SCHEDULES_EVERY_MINUTE.union(TEST_SCHEDULES_SINGLE_MINUTES)


def dynamic_alert_minimum_interval(**kwargs) -> int:
return int(timedelta(minutes=10).total_seconds())


def dynamic_report_minimum_interval(**kwargs) -> int:
return int(timedelta(minutes=5).total_seconds())


def app_custom_config(
alert_minimum_interval: int | str = 0,
report_minimum_interval: int | str = 0,
alert_minimum_interval: int | str | Callable[[], int] = 0,
report_minimum_interval: int | str | Callable[[], int] = 0,
) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
"""
Decorator to mock the current_app.config values dynamically for each test.
Expand Down Expand Up @@ -253,3 +261,37 @@ def test_validate_report_frequency_invalid_config(
f"invalid value for {report_type}_MINIMUM_INTERVAL: 10 minutes"
)
assert expected_error_message.lower() in caplog.text.lower()


@app_custom_config(
alert_minimum_interval=dynamic_alert_minimum_interval,
report_minimum_interval=dynamic_report_minimum_interval,
)
def test_validate_report_frequency_using_callable() -> None:
"""
Test the ``validate_report_frequency`` method when the config
values are set to a function.
"""
# Should fail with a 9 minutes interval, and work with 10
with pytest.raises(ReportScheduleFrequencyNotAllowed):
BaseReportScheduleCommand().validate_report_frequency(
"1,10 * * * *",
ReportScheduleType.ALERT,
)

BaseReportScheduleCommand().validate_report_frequency(
"1,11 * * * *",
ReportScheduleType.ALERT,
)

# Should fail with a 4 minutes interval, and work with 5
with pytest.raises(ReportScheduleFrequencyNotAllowed):
BaseReportScheduleCommand().validate_report_frequency(
"1,5 * * * *",
ReportScheduleType.REPORT,
)

BaseReportScheduleCommand().validate_report_frequency(
"1,6 * * * *",
ReportScheduleType.REPORT,
)
Loading