diff --git a/clickhouse/changelog.d/23553.fixed b/clickhouse/changelog.d/23553.fixed new file mode 100644 index 0000000000000..3878c76b9271a --- /dev/null +++ b/clickhouse/changelog.d/23553.fixed @@ -0,0 +1 @@ +Skip emitting empty storage_health payloads when every parts-and-merges collection is empty. \ No newline at end of file diff --git a/clickhouse/datadog_checks/clickhouse/parts_and_merges.py b/clickhouse/datadog_checks/clickhouse/parts_and_merges.py index a43510a4c3b02..97dc7246ae919 100644 --- a/clickhouse/datadog_checks/clickhouse/parts_and_merges.py +++ b/clickhouse/datadog_checks/clickhouse/parts_and_merges.py @@ -818,6 +818,8 @@ def _emit_events( thresholds: list[dict] | None = None, ) -> None: """Emit a per-cycle row-level payload consumed by dbm-events-processor.""" + if not (parts or merges or mutations or replication_queue or detached_parts or thresholds): + return now_ms = int(time.time() * 1000) payload = { "host": self._check.reported_hostname, diff --git a/clickhouse/tests/test_parts_and_merges.py b/clickhouse/tests/test_parts_and_merges.py index 8a454ac761f7c..200c449ea08c8 100644 --- a/clickhouse/tests/test_parts_and_merges.py +++ b/clickhouse/tests/test_parts_and_merges.py @@ -856,12 +856,27 @@ def test_emit_events_uses_query_activity_channel_not_metadata(check): mock.patch('datadog_checks.clickhouse.parts_and_merges.datadog_agent') as agent_mock, ): agent_mock.get_version.return_value = '7.64.0' - job._emit_events([], [], [], [], []) + job._emit_events(_collected_parts(), [], [], [], []) activity_mock.assert_called_once() metadata_mock.assert_not_called() +def test_emit_events_skips_when_all_collections_empty(check): + job = check.parts_and_merges + job.tags = ['test:clickhouse'] + job._tags_no_db = ['test:clickhouse'] + + with ( + mock.patch.object(check, 'database_monitoring_query_activity') as activity_mock, + mock.patch('datadog_checks.clickhouse.parts_and_merges.datadog_agent') as agent_mock, + ): + agent_mock.get_version.return_value = '7.64.0' + job._emit_events([], [], [], [], [], []) + + activity_mock.assert_not_called() + + # ----------------------------------------------------------------------------- # Error handling # ----------------------------------------------------------------------------- @@ -907,6 +922,29 @@ def test_collect_and_emit_runs_with_partial_failures(check): assert payload['clickhouse']['active_merges'] == _collected_merges() +def test_collect_and_emit_skips_when_all_collectors_empty(check): + job = check.parts_and_merges + job.tags = ['test:clickhouse'] + job._tags_no_db = ['test:clickhouse'] + + with ( + mock.patch.object(job, '_collect_parts', return_value=[]), + mock.patch.object(job, '_collect_merges', return_value=[]), + mock.patch.object(job, '_collect_mutations', return_value=[]), + mock.patch.object(job, '_collect_mutations_aggregated', return_value=[]), + mock.patch.object(job, '_collect_replication_queue', return_value=[]), + mock.patch.object(job, '_collect_replication_queue_aggregated', return_value=[]), + mock.patch.object(job, '_collect_detached_parts', return_value=[]), + mock.patch.object(job, '_collect_thresholds', return_value=[]), + mock.patch.object(check, 'database_monitoring_query_activity') as activity_mock, + mock.patch('datadog_checks.clickhouse.parts_and_merges.datadog_agent') as agent_mock, + ): + agent_mock.get_version.return_value = '7.64.0' + job._collect_and_emit() + + activity_mock.assert_not_called() + + # ----------------------------------------------------------------------------- # Cluster routing # -----------------------------------------------------------------------------