[Python] Honor disableCounterMetrics, disableStringSetMetrics and disableBoundedTrieMetrics experiments - #40165
Conversation
|
Checks are failing. Will not request review until checks are succeeding. If you'd like to override that behavior, comment |
|
Run Yaml_Xlang_Direct PreCommit |
|
Assigning reviewers: R: @shunping for label python. This pull request likely touches a core component ("core" label). Please review with scrutiny. Note: If you would like to opt out of this review, comment Available commands:
The PR bot will only process comments in the main thread (not review comments). |
|
The five |
…ableBoundedTrieMetrics experiments Re-lands the feature from apache#38749 (reverted in apache#38901) without changing the public surface of the metric objects. The Java SDK lets high throughput jobs turn off metric kinds that pressure the metrics backend via these experiments; the Python SDK now does the same. Instead of replacing DelegatingCounter.inc / DelegatingStringSet.add / DelegatingBoundedTrie.add with methods (which broke callers passing the value as a keyword and code relying on them being MetricUpdater instances), the gate lives in MetricUpdater.__call__ and is keyed by cell type. With no experiment set it is a truthiness check on an empty set, so the hot path is unchanged. MetricsFlag.set_default_pipeline_options mirrors the Java MetricsFlag and is applied when a Pipeline is constructed and at SDK worker harness start-up, first call wins as in Java. Fixes apache#38746 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
43f69f3 to
050fb02
Compare
The process-wide metrics container is shared with every other test in the pytest-xdist worker process, so asserting it is empty fails whenever another test (the GCP suites in the cloud tox env) registered a process-wide counter first.
|
The |
|
@shunping is there anything else you'd like changed here? The earlier macOS failures were the deltalake wheel issue. |
|
Adding @Abacn since he made the last revert. |
|
Let me run an internal import |
| _LOGGER = logging.getLogger(__name__) | ||
|
|
||
|
|
||
| class MetricsFlag(object): |
There was a problem hiding this comment.
Besides the method signature change, I remember another breakage introduced in the first attempt was a circular import. For precaution can we move the new logic into a new metrics_flag.py with minimum required import, to avoid potential issues in callers?
| if debug_options.lookup_experiment(experiment): | ||
| disabled.add(cell_type) | ||
| _LOGGER.info('%s metrics are disabled.', kind) | ||
| execution.set_disabled_cell_types(disabled) |
There was a problem hiding this comment.
if we put metrics_flag in a separate module, we can query disabled cells from execution.py and no need to import execution here
| """ | ||
| if cls._initialized: | ||
| return | ||
| debug_options = options.view_as(DebugOptions) |
There was a problem hiding this comment.
consider import debug options in place. Currently no non-test file in apache_beam/metrics/ imported apache_beam.options at runtime, as a pre-caution for circular import risk
Re-lands #38749 (reverted in #38901) so the Python SDK honors the
disableCounterMetrics,disableStringSetMetricsanddisableBoundedTrieMetricsexperiments the way the Java SDK already does, letting high-throughput jobs stop reporting metric kinds that put pressure on the metrics backend.Why the first attempt broke, and what is different here. #38749 replaced
DelegatingCounter.inc(and theadds onDelegatingStringSet/DelegatingBoundedTrie) — which areMetricUpdaterinstance attributes with signature__call__(value=_DEFAULT)— with plain methodsinc(self, n=1). That broke callers usingcounter.inc(value=...)(thread) and anything relying on those attributes beingMetricUpdaterinstances (pickling viaMetricUpdater.__reduce__,isinstancechecks). This PR leaves the metric objects untouched:MetricUpdater.__call__(metrics/execution.py) drops the update when its cell type is in a module-level_DISABLED_CELL_TYPESset. With no experiment set this is a truthiness check on an empty set, so the hot path is unchanged; with one set it is a single set lookup. Declared inexecution.pxdfor the Cython build.MetricsFlag(metrics/metric.py) mirrors the JavaMetrics.MetricsFlag:set_default_pipeline_options(options)maps the three experiments ontoCounterCell/StringSetCell/BoundedTrieCell, logs which kinds are disabled, and — as in Java — the first call wins so user code on a worker cannot change what the harness started with.reset()exists for tests.Pipeline.__init__(so the DirectRunner honors it) andsdk_worker_main.create_harness(portable workers), next to the existingFileSystems.set_optionscalls, same as [Python] Honor disableCounterMetrics, disableStringSetMetrics, and disableBoundedTrieMetrics experiments #38749.Because the gate is evaluated per call rather than captured at construction, it also covers metric objects created before the options were known (module-level counters, DoFns constructed before
Pipeline(...)) and objects unpickled on the worker.Tests (
metric_test.py::MetricsFlagTest, 9 cases): experiments → flags for each kind and combined; first-call-wins; a regression test thatinc(),inc(4),inc(value=5),dec(),add(value=...)all still work andcounter.incis still aMetricUpdater; each disabled kind is a no-op for objects created before and after the flag while other kinds keep reporting; process-wide counters; unpickled metrics; and an end-to-endTestPipelinewith--experiments=disableCounterMetricsasserting the counter is absent from results while the distribution is intact. Without the implementation the suite fails.Run locally on Windows (pure-Python build):
pytest apache_beam/metrics/ pipeline_test.py runners/worker/sdk_worker_main_test.py runners/worker/statesampler_test.py→ 109 passed (one pre-existingpipeline_testfailure from a dill version mismatch in my env),ruff check,yapf,pylintclean on touched files,mypyclean formetrics/execution.pyandmetrics/metric.py. Prepared with AI assistance (Claude Code) and human-verified.fixes #38746
Thank you for your contribution! Follow this checklist to help us incorporate your contribution quickly and easily:
addresses #123), if applicable. This will automatically add a link to the pull request in the issue. If you would like the issue to automatically close on merging the pull request, commentfixes #<ISSUE NUMBER>instead.CHANGES.mdwith noteworthy changes.🤖 Generated with Claude Code