Skip to content

[FLINK-40294][table-planner] Instrument async scalar and table UDF calls with metrics - #29007

Draft
weiqingy wants to merge 3 commits into
apache:masterfrom
weiqingy:flink-38071-pr3-async
Draft

[FLINK-40294][table-planner] Instrument async scalar and table UDF calls with metrics#29007
weiqingy wants to merge 3 commits into
apache:masterfrom
weiqingy:flink-38071-pr3-async

Conversation

@weiqingy

Copy link
Copy Markdown
Contributor

This is the third PR of the FLIP-485 implementation, split into a stack of small, independently reviewable PRs under the umbrella issue FLINK-38071. Landing order:

Step Sub-task Scope
PR-1 ✅ merged FLINK-40292 UdfMetrics helper: registration, sampling, timing, exception counting (#28878)
PR-2 🔵 in review FLINK-40293 Config options + sync scalar/table instrumentation (#28879)
PR-3 (this PR) FLINK-40294 Async scalar/table instrumentation
PR-4 FLINK-40295 User-facing documentation

Stacked on #28879 and kept as a draft until that merges, so the diff here currently also shows PR-2's commit. It will collapse to this step's changes once PR-2 lands.

What is the purpose of the change

Extends the FLIP-485 UDF metrics to asynchronous scalar and table functions, so udfProcessingTime and udfExceptionCount cover the async paths as well as the synchronous ones.

An async invocation does not begin and end on the same thread, so the instrumentation is split. At dispatch, on the task thread, the sampling decision is taken and the start timestamp captured. At completion, on the callback thread, the elapsed time is recorded and an exceptional completion increments the counter. udfProcessingTime therefore measures the full dispatch-to-completion span, not just the synchronous hand-off.

Brief change log

  • Emit the dispatch-side instrumentation for the async scalar and async table call sites in AsyncCodeGenerator and BridgingFunctionGenUtil.
  • Record completion in the per-invocation delegating futures, DelegatingAsyncResultFuture (async scalar) and DelegatingAsyncTableResultFuture (async table).
  • Add a single-handle accessor to CodeGeneratorContext so the generated fetcher resolves the shared UdfMetrics handle.
  • Write the sample decision and start timestamp before registering the completion callback, establishing a happens-before edge to the callback thread. The histogram is synchronized and the exception counter is thread-safe.

As on the synchronous path, the instrumentation is emitted at code generation only when table.exec.udf-metric-enabled is true, so the generated code is unchanged when the feature is disabled.

Known limitation: an async scalar call whose arguments are all null short-circuits but still flows through the future, so with metrics enabled it records one near-zero histogram entry. This is a bounded skew in the timing distribution, not a correctness issue; avoiding it cleanly needs a separate dispatch path for the short-circuit case.

Verifying this change

This change added tests and can be verified as follows:

  • New async cases in UdfMetricsITCase: async scalar and async table metrics, naming and scope, and an exceptional completion that increments udfExceptionCount while the job still finishes.
  • The existing AsyncCalcITCase and AsyncCorrelateITCase suites guard the async paths against regressions.

Does this pull request potentially affect one of the following parts:

  • Dependencies (does it add or upgrade a dependency): no
  • The public API, i.e., is any changed class annotated with @Public(Evolving): no
  • The serializers: no
  • The runtime per-record code paths (performance sensitive): yes, the async dispatch and completion paths. Gated at code generation, so the generated code is unchanged when the feature is disabled.
  • Anything that affects deployment or recovery: JobManager (and its components), Checkpointing, Kubernetes/Yarn, ZooKeeper: no
  • The S3 file system connector: no

Documentation

  • Does this pull request introduce a new feature? yes
  • If yes, how is the feature documented? JavaDocs here; the metrics.md section lands in PR-4.

Was generative AI tooling used to co-author this PR?
  • Yes (please specify the tool below)

Generated-by: Claude Code (Anthropic Claude Opus 4.8 and Claude Opus 5)

…c scalar and table UDF calls

Introduce two opt-in configuration options for FLIP-485 UDF metrics:
table.exec.udf-metric-enabled (default false) and
table.exec.udf-metric.sample-interval (default 100).

Wrap the generated eval call site for sync scalar and table user-defined
functions (via the BridgingSqlFunction stack) with sampled udfProcessingTime
timing and udfExceptionCount counting, using the UdfMetrics helper registered
on the operator metric group under udf.<udfName>. Instrumentation is emitted
only when table.exec.udf-metric-enabled is true; the generated operator is
byte-identical when disabled. One shared handle is registered per (operator,
udfName). Lookup-join, ML-predict, vector-search, legacy CallGens, and
PROCESS_TABLE functions are not metered.
@flinkbot

flinkbot commented Aug 24, 2026

Copy link
Copy Markdown
Collaborator

CI report:

Bot commands The @flinkbot bot supports the following commands:
  • @flinkbot run azure re-run the last Azure build

…d tests

Document that table.exec.udf-metric.sample-interval must be at least 1 and that
a value of 1 measures every invocation, matching the check in
UdfMetrics.register, and regenerate the config docs.

Reword the async table function correlate comment so it no longer reads as if
that path were already metered; it supplies the UDF name that instrumented call
generators scope their metrics under.

Fail fast when SleepyDoubler is interrupted instead of skipping the sleep, so an
interruption surfaces as itself rather than as a confusing timing assertion
failure.
…lls with metrics

Extend the FLIP-485 UDF metrics to async scalar and table user-defined
functions. The sampling decision and the start timestamp are captured at
dispatch on the task thread; the elapsed time and any exceptional completion
are recorded at completion on the callback thread, in the per-invocation
DelegatingAsyncResultFuture and DelegatingAsyncTableResultFuture. Both writes
happen before the completion callback is registered, establishing a
happens-before edge to the callback thread; the histogram is synchronized and
the exception counter is thread-safe.

udfProcessingTime for an async function therefore spans the full dispatch to
completion, not just the synchronous hand-off. As on the sync path, the
instrumentation is emitted at code generation only when
table.exec.udf-metric-enabled is true.
@weiqingy
weiqingy force-pushed the flink-38071-pr3-async branch from f21ab53 to 0440e15 Compare August 25, 2026 05:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants