Skip to content

DBMON-6747 ClickHouse Async Inserts Monitoring Buffer State Collection - #24517

Open
jenny-chung wants to merge 34 commits into
masterfrom
jenny-chung/clickhouse-async-inserts
Open

DBMON-6747 ClickHouse Async Inserts Monitoring Buffer State Collection#24517
jenny-chung wants to merge 34 commits into
masterfrom
jenny-chung/clickhouse-async-inserts

Conversation

@jenny-chung

@jenny-chung jenny-chung commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

Add buffer state collection for async inserts in ClickHouse. It collects snapshots from system.asynchronous_inserts, including pending bytes, pending entry count, active buffer count, and each buffer's scheduled flush deadline. This collection logic shares the existing query samples job instead of running as its own job to avoid the overhead of a new connection.

Motivation

Support for diagnosing ClickHouse asynchronous inserts in DBM. We can't tell if a buffer is backing up, how big it's getting, or when its pending data is scheduled to flush, so this gives us a way to actually diagnose these issues instead of manually querying the system.* tables.

Agent payload (in mitm proxy):
Screenshot 2026-07-13 at 6 46 37 PM

Review checklist (to be filled by reviewers)

  • Feature or bugfix MUST have appropriate tests (unit, integration, e2e)
  • Add qa/required if this PR needs QA validation, or qa/skip-qa if it does not. Exactly one of the two is required.
  • If you need to backport this PR to another branch, you can add the backport/<branch-name> label to the PR and it will automatically open a backport PR once this one is merged

@jenny-chung jenny-chung changed the title DBMON-6747 DBMON-6747 ClickHouse Async Inserts Monitoring Buffer State Collection Jul 10, 2026
@datadog-datadog-prod-us1

datadog-datadog-prod-us1 Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Tests  Code Coverage

🎉 All green!

🧪 All tests passed
❄️ No new flaky tests detected

🎯 Code Coverage (details)
Patch Coverage: 78.54%
Overall Coverage: 93.38% (+5.01%)

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: 069b175 | Docs | Datadog PR Page | Give us feedback!

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 918a5c439d

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

arbitrary_types_allowed=True,
frozen=True,
)
asynchronous_insert_buffer_snapshot: Optional[AsynchronousInsertBufferSnapshot] = None

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Update the defaults test for the new field

Adding this InstanceConfig annotation without adding asynchronous_insert_buffer_snapshot to clickhouse/tests/test_config_defaults.py makes test_all_config_defaults fail: that test compares InstanceConfig.__annotations__ against EXPECTED_DEFAULTS and explicitly fails for any missing field. The ClickHouse unit suite will therefore reject this change even though the runtime default is provided in dict_defaults.py.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in commit d8febb3

Comment on lines +113 to +115
self.statement_samples = ClickhouseStatementSamples(
self, self._config.query_samples, self._config.asynchronous_insert_buffer_snapshot
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Decouple buffer snapshots from query samples

This wires the buffer snapshot only through ClickhouseStatementSamples, which is constructed under the query_samples.enabled guard immediately above and scheduled at query_samples.collection_interval. If an operator enables asynchronous_insert_buffer_snapshot while disabling query samples, no buffer events are emitted; if they raise the query-samples interval above the buffer interval, snapshots are silently under-collected. Since the new option is documented as its own DBM feature requiring only dbm: true, it needs to be scheduled when the buffer feature is enabled rather than depending on query samples.

Useful? React with 👍 / 👎.

@jenny-chung jenny-chung Jul 13, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in commits 23635e1 and c25b6e4

@jenny-chung
jenny-chung marked this pull request as draft July 10, 2026 21:50
@jenny-chung jenny-chung added the qa/required QA is required for this PR and will generate a QA card label Jul 10, 2026
@jenny-chung
jenny-chung force-pushed the jenny-chung/clickhouse-async-inserts branch from 75590a5 to 23635e1 Compare July 13, 2026 18:22
@jenny-chung
jenny-chung marked this pull request as ready for review July 13, 2026 22:21

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e3f1f53ed3

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

if buffer_config.enabled:
enabled_intervals.append(buffer_config.collection_interval)
collection_interval = (
math.gcd(*(int(i) for i in enabled_intervals)) if enabled_intervals else samples_collection_interval

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve fractional collection intervals

When an existing user sets query_samples.collection_interval: 0.5 or enables the new buffer snapshot with collection_interval: 0.5, this truncates the positive float to 0, so the subsequent rate_limit=1 / collection_interval raises during check initialization. The config schema accepts number values and validation only rejects intervals <= 0, so positive fractional intervals that previously worked now crash instead of being scheduled at the requested rate.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed division by zero error to preserve fractional collection intervals - c7e90e7

## Enable collection of asynchronous insert buffer snapshots from system.asynchronous_inserts.
## Requires `dbm: true`. Sends per-buffer records as DBM events (dbm_type="async_inserts_buffer")
## including the query text, showing bytes pending, pending entry count, and oldest
## entry age per buffer.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This says oldest entry age per buffer but looks like we emit flush_deadline_us. Lets confirm the correct behavior with the CH folks and update this description and the field correctly to match what we emit

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Waiting on confirmation with CH team, but description has been updated in the meantime 5d4c294

raw=True,
)
return []
except Exception as e:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On ClickHouse versions that predate system.asynchronous_inserts, this query raises "Unknown table" every cycle, which this branch logs as a full ERROR stack trace and counts as async_inserts_buffer.error in every collection_interval. Let's have a version check or detect the "unknown table" case and downgrade it to a single warning + skip.

@jenny-chung jenny-chung Jul 24, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added case to detect unknown table and downgrades it to single warning + skip in df0ee69

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we'd want to skip the collection entirely when we see UNKNOWN_TABLE_ERROR_CODE or if version check is possible to avoid the check when the table is not present that would be even better too

elapsed_ms,
)

def _collect_buffer_snapshot(self):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://github.com/DataDog/integrations-core/blob/master/AGENTS.md#python-code-style asks that any new code should provide type hints. let's add these to all new methods

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added type hints - d97bdac


try:
self._collect_samples()
if self._config.enabled and time.time() - self._last_samples_time >= self._collection_interval:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's use one time.time() call here

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to single call in 3bc61f5

assert check.statement_samples._expected_collection_interval == 5


def test_query_samples_independent_of_buffer():

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is nice, but there's no mirror test for the buffer side - i.e. that _collect_buffer_snapshot only fires once per _buffer_collection_interval via _last_buffer_snapshot_time

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added mirror test for buffer side - 09c32cc

@dd-octo-sts

dd-octo-sts Bot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Validation Report

All 21 validations passed.

Show details
Validation Description Status
agent-reqs Verify check versions match the Agent requirements file
ci Validate CI configuration and code coverage settings
codeowners Validate every integration has a CODEOWNERS entry
config Validate default configuration files against spec.yaml
dep Verify dependency pins are consistent and Agent-compatible
http Validate integrations use the HTTP wrapper correctly
imports Validate check imports do not use deprecated modules
integration-style Validate check code style conventions
jmx-metrics Validate JMX metrics definition files and config
labeler Validate PR labeler config matches integration directories
legacy-signature Validate no integration uses the legacy Agent check signature
license-headers Validate Python files have proper license headers
licenses Validate third-party license attribution list
metadata Validate metadata.csv metric definitions
models Validate configuration data models match spec.yaml
openmetrics Validate OpenMetrics integrations disable the metric limit
package Validate Python package metadata and naming
qa-label Validate the pull request declares whether it needs QA for the next Agent release
readmes Validate README files have required sections
saved-views Validate saved view JSON file structure and fields
version Validate version consistency between package and changelog

View full run

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants