Repository navigation
feat: deliver gated host configuration snapshots - #1927
Open
Rohit Ranjan (RohitRanjanMS) wants to merge 10 commits into
Open
Rohit Ranjan (RohitRanjanMS) wants to merge 10 commits into
Rohit Ranjan (RohitRanjanMS) wants to merge 10 commits into
Conversation
Add APP-01 snapshot delivery to classic and library runtimes, canonical protocol fields, and the R2P2 adapter/codec without changing initialization outcomes. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
|
Azure Pipelines: There may be pipelines that require an authorized user to comment /azp run to run. |
Rohit Ranjan (RohitRanjanMS)
marked this pull request as ready for review
November 4, 2026 01:15
Rohit Ranjan (RohitRanjanMS)
requested review from
Gavin Aguiar (gavin-aguiar),
hallvictoria and
Varad Meru (vrdmr)
as code owners
November 4, 2026 01:15
Port token-preserving JSONC normalization and cached fixed-reason diagnostics from dotnet-worker commit 4c440d8d38526a16eb549ac6fba1082fe5ad4450. Preserve strict decoding, byte limits, capability gating and initialization outcomes across classic and library runtimes. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
🔵 Needs a closer look
Cross-language startup and native response codec changes require maintainer validation because Rust/PyO3, Python 3.15, and native Linux checks remain outstanding, while Host integration evidence predates the normalization changes.
No open issues 🎉
2 files not reviewed
runtimes/v1/tests/protos/FunctionRpc_pb2.py: Generated fileruntimes/v2/tests/protos/FunctionRpc_pb2.py: Generated file
What changed in this PR
Adds capability-gated host.json snapshot delivery across the classic Python worker, both library runtimes, and R2P2, while leaving configuration interpretation and acceptance to the Host.
Changes:
- Adds bounded decoding, JSONC normalization, generation-scoped caching, and content-free failure diagnostics.
- Extends all three protocol schemas, Python exports, and R2P2 adapters to transport the optional snapshot.
- Adds contract, initialization, specialization, and serialization tests, plus integration and release documentation.
This is a source implementation; runtime-wheel publication and pin rollout remain prerequisites. Native Rust, Linux, and Python 3.15 validation remain outstanding, as documented.
| File | Description |
|---|---|
workers/tests/unittests/test_host_configuration.py |
Tests classic initialization delivery and specialization reset. |
workers/tests/unittest_r2p2/test_protos_adapter.py |
Tests snapshot status, bytes, and field presence. |
workers/tests/unittest_r2p2/test_host_configuration.py |
Adds shared helper contract tests and drift prevention. |
workers/tests/unittest_r2p2/test_bridge_runtime.py |
Tests source-runtime delivery through the Python bridge. |
workers/tests/unittest_proxy/test_dispatcher.py |
Tests opaque forwarding through proxy envelopes. |
workers/r2p2/src/control.rs |
Maps snapshots to Rust protobuf messages and adds round-trip coverage. |
workers/r2p2/proto/FunctionRpc.proto |
Adds the snapshot message and response field 6. |
workers/r2p2/bridge/protos_adapter.py |
Adds snapshot representation and optional serialization. |
workers/proxy_worker/protos/_src/src/proto/FunctionRpc.proto |
Adds the canonical snapshot contract for proxy transport. |
workers/proxy_worker/protos/__init__.py |
Exports HostConfiguration. |
workers/azure_functions_worker/protos/_src/src/proto/FunctionRpc.proto |
Adds the canonical snapshot contract for classic transport. |
workers/azure_functions_worker/protos/__init__.py |
Exports HostConfiguration. |
workers/azure_functions_worker/host_configuration.py |
Implements gated capture, normalization, caching, and diagnostics. |
workers/azure_functions_worker/dispatcher.py |
Attaches snapshots during initialization and resets on specialization. |
runtimes/v2/tests/unittests/test_host_configuration.py |
Tests v2 delivery, initialization failures, and generation reset. |
runtimes/v2/tests/protos/FunctionRpc_pb2.py |
Regenerates v2 protocol fixtures with snapshot support. |
runtimes/v2/tests/protos/__init__.py |
Exports the snapshot test message. |
runtimes/v2/azure_functions_runtime/host_configuration.py |
Adds the independently packaged v2 snapshot helper. |
runtimes/v2/azure_functions_runtime/handle_event.py |
Integrates snapshots into v2 initialization and specialization. |
runtimes/v1/tests/unittests/test_host_configuration.py |
Tests v1 delivery, initialization errors, and generation reset. |
runtimes/v1/tests/protos/FunctionRpc_pb2.py |
Regenerates v1 protocol fixtures with snapshot support. |
runtimes/v1/tests/protos/__init__.py |
Exports the snapshot test message. |
runtimes/v1/azure_functions_runtime_v1/host_configuration.py |
Adds the independently packaged v1 snapshot helper. |
runtimes/v1/azure_functions_runtime_v1/handle_event.py |
Integrates snapshots into v1 initialization and specialization. |
README.md |
Documents delivery behavior, protocol generation, and rollout prerequisites. |
Review effort: Balanced
Collaborator
|
/azp run |
|
Azure Pipelines: Successfully started running 1 pipeline(s). |
Match dotnet-worker e7765e7 by rejecting decoded empty and non-object JSON with cached InvalidJson outcomes. Preserve token normalization, strict decoding, byte/depth limits and existing initialization behavior. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Contributor
|
/azp run |
|
Azure Pipelines: Successfully started running 1 pipeline(s). |
Restore the classic worker and unit-test tree to the baseline. Retain proxy/R2P2 delivery through the v1/v2 runtime helpers, scope shared tests accordingly, and clarify process-environment and reload behavior. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Collaborator
|
/azp run |
|
Azure Pipelines: Successfully started running 1 pipeline(s). |
Preserve both the host-configuration envelope tests and the incoming BYOC connection tests in the proxy dispatcher suite. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
hallvictoria
reviewed
Nov 5, 2026
Keep implementation and rollout details in the pull request description rather than the customer-facing repository overview. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Contributor
|
/azp run |
|
Azure Pipelines: Successfully started running 1 pipeline(s). |
Apply the rustfmt layout required by the R2P2 CI formatting check without changing test tokens or behavior. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Contributor
|
/azp run |
|
Azure Pipelines: Successfully started running 1 pipeline(s). |
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Relates to Azure/azure-functions-host#12049 (non-closing).
Port APP-01 Host Configuration delivery to Python 3.13+ proxy/R2P2, through both independently packaged v1/v2 library runtimes. The classic worker (
workers/azure_functions_worker, Python <=3.12) is unchanged from the PR baseline and does not implement delivery. This reflects the explicitly approved scope reduction in4a694c9dd78d2a10115c344f3cd5d04316139cb0; the earlier reply retaining classic coverage has been corrected in the review thread.This is source implementation and validation, not a claim that existing published runtime wheels already contain the feature.
WorkerInitRequest.capabilities["HostConfiguration"] == "1"; otherwise omit the field without obtaining the application root, reading a file, initializing the snapshot, or emitting delivery diagnostics.host.jsonbeneath worker-localFUNCTIONS_APPLICATION_DIRECTORY, preserving explicitly configured relative paths and distinguishing a missing file at open from an unavailable/missing parent. No Host-supplied-directory, worker-directory, or implicit cwd fallback. Not-found errors during reading/closing areError, notMissing.TooLarge; non-Available outcomes contain no bytes.//and/* */comments and trailing commas. Preserve raw number spellings, string/property escapes, duplicate keys and key order. Require exactly one object root and at most 64 nested containers.{}and nested arrays/scalars inside an object remain valid. Empty/BOM-only files, non-object roots (including after comments), malformed JSON and whitespace/comment-only input produce content-freeError/InvalidJson.HostConfigurationmessage/comments to the proxy and R2P2 vendored schemas, proxy protobuf exports, R2P2's handwritten adapter, and its explicit Rust response mapping. v1/v2 distributions carry identical package-local helpers; shared tests prevent drift without importing classic code or another runtime distribution.Reference pins
8701c546f6bb4d4305d1f498f35f3ad1b5539351.4a694c9dd78d2a10115c344f3cd5d04316139cb0, following object-root parity commita8893673f1c98122a4a151e7ffcb87775b5d1c2f.313666583af4e97f0b534f1cbf61a3812f277c12when originally checked. Only APP-01 was vendored into the retained proxy/R2P2 schemas; unrelated upstream fields and local language options were not changed.HostConfigurationSnapshotProvider.cs, throughe7765e7201008340e4cc407486bbd31649abf162. This adds empty/non-object rejection to normalization/diagnostic semantics from4c440d8d38526a16eb549ac6fba1082fe5ad4450(original delivery reference6066d8c6597c8f9810a4467d10aea0ac4a58d62d).8da994a4e19324233a6f0efecea963a5cc5c5c03.Normalization details: escaped lone/reversed surrogates remain unchanged; numeric tokens are never converted to Python integers/floats, avoiding digit limits, rounding and overflow (
-0,1E+2,1e999, large/precise values). U+2028/U+2029 are invalid inside line comments or as JSON whitespace, but valid inside block comments and strings. Python's strict decoders accept legitimately encoded U+FFFD with or without a BOM; this intentionally does not copy the .NETStreamReaderreplacement-character workaround. The scope reduction changes no retained runtime normalization, dependencies or published pins.Environment and reload boundaries
FUNCTIONS_APPLICATION_DIRECTORYis an ordinary process environment variable, not protected from customer Python code. A mutation after capture does not change the cached snapshot. Runtime environment reload clears/replacesos.environfrom the incoming request and resets the snapshot under the capture lock; this variable is not exempted or preserved. Reload itself does not read or deliver configuration: its response has only the existing metadata/capabilities/result fields. A subsequent exact-capability initialization could capture the replacement root. This is not a new reload-delivery mechanism or a guarantee that Host would adopt a replacement snapshot; Host acceptance/lifetime policy is separate. The launcher must provision the root/mount before first enabled initialization—there is no worker readiness barrier or retry.Validation performed for the Python 3.13+ scope reduction
Executed using local Python 3.14.3 (
.venv314) for retained runtime/bridge behavior and Python 3.11.9 (.venv) only for classic baseline regressions, generation and lint. Test commands set$env:PYTHONDONTWRITEBYTECODE='1'. No dependencies were installed and no tests/CI gates were weakened.From the repository root:
Passed: 600 tests, 34 deselected. The count is lower solely because the classic helper parameter was removed; all existing v1/v2 cases remain. These exercise the Python source runtimes/bridge/adapter, not the native Rust binary. Coverage includes exact gating/no IO, all encodings/BOM-only failures, object-root validation, raw tokens/duplicates, U+FFFD, exact byte limits, depth64, cached/concurrent outcomes, warnings/redaction, fresh envelopes and unchanged init results.
From each of
runtimes\v1andruntimes\v2, with$env:PYTHONPATH=(Get-Location).Path:Passed: v1 35 tests, 2 deselected, 11 warnings; v2 43 tests, 4 deselected, 11 warnings. Feature specialization tests run with their existing process-local Windows
time.tzsetmocks. Existing tests namedenvironment_reloadare outside this selector; no lifecycle implementation changed in this follow-up and these results are not native Linux evidence.From
workers, with$env:PYTHONPATH=(Get-Location).Path:Passed: proxy 37 tests, 6 existing warnings; classic baseline regressions 18 tests, 9 pre-existing Python-version-specific skips, 118 deselected. Classic feature-specific tests were removed with the unsupported implementation; no pre-existing classic tests were removed. The classic source and unit-test tree exactly match the baseline.
From
workers\tests:Passed. Regenerated ignored local classic bindings from the restored baseline schema using the existing generator; no generated output was hand-edited. This also cleaned stale worker build output before packaging. The classic generated descriptor has no
HostConfigurationtype/field; the unchanged proxy descriptor retains field 6.From the repository root:
All passed. An initial flake8 invocation without the repository configuration reported baseline
__init__.pyre-export F401s; the repository-configured check above passes without changing those exports or the lint policy. Retained runtime/proxy/R2P2 product files are unchanged by this scope-reduction commit. The resulting full PR diff contains 20 files and none under the classic worker or classic unit-test tree.Packaging and local wheel verification, from the repository root (session artifacts, no publication/pin changes):
Both passed. Three wheels built. The session-artifact smoke script confirms the worker wheel lacks the classic helper/message/response field while retaining proxy field 6. Both runtime-wheel helpers match source exactly; disabled no-capture plus 16 cached-delivery/warning/envelope cases per runtime (32 total) pass. A process-local probe using each runtime's actual sync executor also confirms customer
os.environmutation is visible but leaves cached delivery unchanged until reset. This does not simulate Host reload/adoption. These are locally built source wheels, not updated published artifacts.Integration evidence and known validation gaps
The coordinator's earlier
python worker-config-e2e.py --languages pythonrun passed seven cases using the classic worker and real native Windows Host/C# WorkerProxy at Host8da994a4e19324233a6f0efecea963a5cc5c5c03(evidence: parentfiles\worker-config-e2e-20261103-112110\results.json). That classic delivery implementation has now been removed. Those historical results are not evidence for the current Python 3.13+ proxy/R2P2 scope. No new real Host/WorkerProxy integration or mount-readiness test was run for this revision.The retained runtime test protobuf fixtures were originally regenerated using
grpc_tools.protoc --python_outandtest_setup.make_absolute_imports, preserving local language options. Each has 194 added / 179 removed lines from compiler header/runtime checks and serialized descriptor offsets; prior descriptor comparison confirmed pre-existing schema unchanged. Only the proxy/R2P2 vendored schemas now carry APP-01.Native Rust/Python 3.15 build/tests/rustfmt/clippy remain unverified locally (
cargois unavailable). The adapter-to-prost round-trip test is authored but has not executed here. Native Linux validation of this revision remains outstanding.CI infrastructure blocker is separate from product scope. Azure Pipelines build 313889, on the prior HEAD's merge commit, failed before R2P2 compilation because the approved Cargo feed returned HTTP 401 for uncached
portable-atomic; the v2 job failed before tests when Python 3.13 download returned HTTP 504. Cargo/dependency/feed/job configuration is unchanged by this PR. The user chose to leave this for a pipeline/feed maintainer to repair access and rerun. No feed bypass, dependency workaround, extra trigger comment or CI waiver was added. This description does not claim CI on the newly pushed HEAD has passed.Release/integration prerequisites
FUNCTIONS_APPLICATION_DIRECTORYand establish root/mount readiness before first enabled init; Python does not provide either guarantee.workers/pyproject.toml:42-43: runtime v21.3.0, runtime v11.2.0.eng/pack/scripts/r2p2_deps.sh:169-170andeng/pack/scripts/r2p2_deps.ps1:156-157: runtime v21.2.1, runtime v11.1.0.Pull Request Checklist
Host-Worker Contract
Worker Execution Logic
If yes, please answer the following:
Python Version Coverage
Programming Model Compatibility (proxy_worker and r2p2)