This is an automated email from the ASF dual-hosted git repository.

vavila pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/superset.git


The following commit(s) were added to refs/heads/master by this push:
     new 3dadefcfb0 feat: Support a dynamic minimum interval for alerts and 
reports (#29241)
3dadefcfb0 is described below

commit 3dadefcfb0f0f2da159bec549ca1ed87263a31b6
Author: Vitor Avila <[email protected]>
AuthorDate: Thu Jun 13 19:12:45 2024 -0300

    feat: Support a dynamic minimum interval for alerts and reports (#29241)
---
 docs/docs/configuration/alerts-reports.mdx    | 11 +++++++
 superset/commands/report/base.py              |  2 ++
 superset/config.py                            |  1 +
 tests/unit_tests/commands/report/base_test.py | 46 +++++++++++++++++++++++++--
 4 files changed, 58 insertions(+), 2 deletions(-)

diff --git a/docs/docs/configuration/alerts-reports.mdx 
b/docs/docs/configuration/alerts-reports.mdx
index d489b6ebd7..ed4e739aea 100644
--- a/docs/docs/configuration/alerts-reports.mdx
+++ b/docs/docs/configuration/alerts-reports.mdx
@@ -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.
diff --git a/superset/commands/report/base.py b/superset/commands/report/base.py
index 3086023f03..199f985d0d 100644
--- a/superset/commands/report/base.py
+++ b/superset/commands/report/base.py
@@ -98,6 +98,8 @@ class BaseReportScheduleCommand(BaseCommand):
             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(
diff --git a/superset/config.py b/superset/config.py
index ea3ac079cf..3dfeb3ad47 100644
--- a/superset/config.py
+++ b/superset/config.py
@@ -1382,6 +1382,7 @@ ALERT_REPORTS_MIN_CUSTOM_SCREENSHOT_WIDTH = 600
 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())
 
diff --git a/tests/unit_tests/commands/report/base_test.py 
b/tests/unit_tests/commands/report/base_test.py
index 871f3a511b..61d233535e 100644
--- a/tests/unit_tests/commands/report/base_test.py
+++ b/tests/unit_tests/commands/report/base_test.py
@@ -52,9 +52,17 @@ TEST_SCHEDULES_SINGLE_MINUTES = {
 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.
@@ -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,
+    )

Reply via email to