Skip to content

[Python][RunInference] Report the model identifier to model handlers - #40906

Merged
damccorm merged 3 commits into
apache:masterfrom
AMOOOMA:pr-model-identifier
Nov 5, 2026
Merged

damccorm merged 3 commits into
apache:masterfrom
AMOOOMA:pr-model-identifier

Conversation

@AMOOOMA

@AMOOOMA AMOOOMA commented Oct 30, 2026

Copy link
Copy Markdown
Contributor

Split out of #40760, following review feedback to separate the generic pieces from the vLLM-specific ones. This PR is a small generic RunInference hook.

Why

Runners that autoscale on num_loaded_models_<model_identifier> (Dataflow's GPU autoscaling) look the metric up by the identifier RunInference annotates the inference step with: the model_identifier passed to RunInference, or a uuid it generates. ModelManager publishes under that identifier (and since #40714 keeps it stable across side-input model updates). But a model handler that publishes the metric itself, e.g. one that fronts an out-of-process model server, has no way to learn that value.

What

  • ModelHandler.set_model_identifier(model_identifier): a no-op by default. _RunInferenceDoFn.setup() calls it on each worker, before the first load_model(), with the same tag it annotates the step with and gives ModelManager.
  • Forwarded by the keyed, maybe-keyed, prebatched, preprocessing and postprocessing wrappers (KeyedModelHandler forwards to every per-key handler).

No behavior change for existing handlers.

Testing

base_test.py:

  • An explicit model_identifier reaches the handler before load_model().
  • Without one, the generated uuid equals the model_identifier annotation on RunInference/BeamML_RunInference.
  • The identifier is forwarded through KeyedModelHandler and pre/post-processing wrappers.

Thank you for your contribution! Follow this checklist to help us incorporate your contribution quickly and easily:

  • Replace these instructions with a description of your change and why you have made it.
  • Mention the appropriate issue in your description (for example: addresses #123 or fixes #456).
  • Update CHANGES.md with noteworthy changes.

Add ModelHandler.set_model_identifier(), which RunInference calls on each
worker before the first load_model() with the step's model_identifier (the
value passed to RunInference, or the uuid it generates). Handlers that
publish num_loaded_models_<identifier> themselves, such as handlers that
front an out-of-process model server, can then use the exact tag the step is
annotated with. The value is stable across side-input model updates,
matching the metric tag ModelManager uses since apache#40714.

The hook is a no-op by default and is forwarded by the keyed, maybe-keyed,
prebatched, preprocessing and postprocessing wrappers.
@github-actions github-actions Bot added python size/s S: 10-49 lines changed labels Oct 30, 2026
@AMOOOMA
AMOOOMA marked this pull request as ready for review October 30, 2026 17:02
@AMOOOMA

AMOOOMA commented Oct 30, 2026

Copy link
Copy Markdown
Contributor Author

R: @damccorm

@github-actions

Copy link
Copy Markdown
Contributor

Stopping reviewer notifications for this pull request: review requested by someone other than the bot, ceding control. If you'd like to restart, comment assign set of reviewers

@codecov

codecov Bot commented Oct 30, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 80.11%. Comparing base (12bbb17) to head (9e3e9e2).
⚠️ Report is 87 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master   #40906      +/-   ##
==========================================
+ Coverage   79.83%   80.11%   +0.27%     
==========================================
  Files         494      494              
  Lines       83575    83673      +98     
==========================================
+ Hits        66722    67034     +312     
+ Misses      16853    16639     -214     
Flag Coverage Δ
python 80.11% <100.00%> (+0.27%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

def setup(self):
self._metrics_collector = self.get_metrics_collector()
self._model_handler.set_environment_vars()
self._model_handler.set_model_identifier(self._model_tag)

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.

Can we call self._model_handler.set_model_identifier(self._model_tag) in RunInference.__init__ right when self._model_tag is created (or in both places)? At that point the user has already constructed and wrapped their ModelHandler, so setting it in RunInference.__init__ means _model_identifier is pickled with the handler and is also immediately inspectable on the handler at pipeline construction time (making unit tests much simpler).

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.

Done in b4c101c, in both places. RunInference.__init__ now calls set_model_identifier(self._model_tag) right after the tag is created, so it is pickled with the handler and visible at construction time. I added construction-time tests for the explicit id, the generated uuid (== _model_tag), wrapper chains, and multi-model KeyedModelHandler. I kept the call in setup() as well, since the construction-time call mutates the user's handler: if one handler instance is shared across RunInferences with different identifiers, the worker still re-sets the right value from the DoFn's own _model_tag.

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.

I kept the call in setup() as well, since the construction-time call mutates the user's handler: if one handler instance is shared across RunInferences with different identifiers, the worker still re-sets the right value from the DoFn's own _model_tag.

Oh interesting, I hadn't thought about this modifying the original underlying model handler in that case. Given that, lets just keep this set call instead of having it in both places. Sorry for the churn

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.

No worries! Updated now.

…ference.__init__

Address review feedback: ModelHandler.set_model_identifier now stores the
value in self._model_identifier (initialized to None in __init__), so
subclasses can read it without overriding. RunInference.__init__ reports
the identifier at construction time so it is pickled with the handler and
inspectable before the pipeline runs; _RunInferenceDoFn.setup() still
re-reports it on the worker.
@github-actions github-actions Bot added size/m M: 50-249 lines changed and removed size/s S: 10-49 lines changed labels Nov 5, 2026
Drop the construction-time call in RunInference.__init__ so the user's
handler is not mutated (a handler shared across RunInference transforms
would otherwise end up with the last identifier). Wrapper forwarding is
now tested by calling set_model_identifier directly.

@damccorm damccorm left a comment

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.

Thanks! Letting tests run and then I will merge

@damccorm
damccorm merged commit fff61b5 into apache:master Nov 5, 2026
87 of 88 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

python size/m M: 50-249 lines changed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants