Skip to content

Resolve key vault references concurrently - #736

Merged
linglingye001 merged 14 commits into
mainfrom
linglingye/resolve-secret-parallel
Jul 24, 2026
Merged

Resolve key vault references concurrently#736
linglingye001 merged 14 commits into
mainfrom
linglingye/resolve-secret-parallel

Conversation

@linglingye001

@linglingye001 linglingye001 commented May 20, 2026

Copy link
Copy Markdown
Member

This PR introduces an opt-in capability to resolve Azure Key Vault references concurrently during Azure App Configuration load, aiming to reduce startup time when many Key Vault references are present. #735

Changes:

  • Add ParallelSecretResolutionEnabled option under Key Vault configuration and plumb it into provider options.
  • Update configuration loading to optionally process adapter resolution concurrently.
  • Add unit tests covering parallel resolution behavior and default sequential behavior

@linglingye001
linglingye001 requested a review from Copilot May 20, 2026 07:47
@linglingye001
linglingye001 force-pushed the linglingye/resolve-secret-parallel branch from 5c8223e to 61295ef Compare May 20, 2026 07:49

Copilot AI 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.

Pull request overview

This PR introduces an opt-in capability to resolve Azure Key Vault references concurrently during Azure App Configuration load, aiming to reduce startup time when many Key Vault references are present.

Changes:

  • Add ParallelSecretResolutionEnabled option under Key Vault configuration and plumb it into provider options.
  • Update configuration loading to optionally process adapter resolution concurrently and merge results deterministically.
  • Add unit tests covering parallel resolution behavior and default sequential behavior; add locking in the Key Vault secret provider to support concurrent access.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
tests/Tests.AzureAppConfiguration/Unit/KeyVaultReferenceTests.cs Adds tests validating parallel Key Vault resolution and default sequential behavior.
src/Microsoft.Extensions.Configuration.AzureAppConfiguration/AzureKeyVaultReference/AzureKeyVaultSecretProvider.cs Adds synchronization around secret caching and refresh bookkeeping for thread safety under concurrency.
src/Microsoft.Extensions.Configuration.AzureAppConfiguration/AzureAppConfigurationProvider.cs Adds parallel adapter processing path and factors merge logic into a helper.
src/Microsoft.Extensions.Configuration.AzureAppConfiguration/AzureAppConfigurationOptions.cs Stores whether parallel secret resolution is enabled after Key Vault configuration.
src/Microsoft.Extensions.Configuration.AzureAppConfiguration/AzureAppConfigurationKeyVaultOptions.cs Introduces the public ParallelSecretResolutionEnabled toggle with documentation.
Comments suppressed due to low confidence (1)

src/Microsoft.Extensions.Configuration.AzureAppConfiguration/AzureAppConfigurationProvider.cs:654

  • In parallel mode, all adapter tasks are dispatched before any failures are observed (via Task.WhenAll). If a single Key Vault reference is invalid/unavailable, the load will still issue requests for the remaining references, increasing latency and side effects (extra Key Vault traffic) even though the overall load fails. Consider failing fast by cancelling remaining work when the first task faults (e.g., linked CancellationTokenSource + cancel on first exception, or processing in bounded batches).
                // Dispatch adapter processing for all settings concurrently. Only Key Vault references
                // perform network I/O during adapter processing; other adapters complete synchronously.
                // Insertion order in 'data' is preserved when merging results so prefix-stripping and
                // last-write-wins behavior remain unchanged.
                var pendingTasks = new List<Task<IEnumerable<KeyValuePair<string, string>>>>(data.Count);

                foreach (KeyValuePair<string, ConfigurationSetting> kvp in data)
                {
                    if (_requestTracingEnabled && _requestTracingOptions != null)
                    {
                        _requestTracingOptions.UpdateAiConfigurationTracing(kvp.Value.ContentType);
                    }

                    pendingTasks.Add(ProcessAdapters(kvp.Value, cancellationToken));
                }

                IEnumerable<KeyValuePair<string, string>>[] results = await Task.WhenAll(pendingTasks).ConfigureAwait(false);

                for (int i = 0; i < results.Length; i++)
                {
                    MergeIntoApplicationData(applicationData, results[i]);
                }
            }

Copilot AI 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.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

@avanigupta

Copy link
Copy Markdown
Member

I'm thinking of a different approach for this PR. What if we added a new method to the IKeyValueAdapter interface which pre-loads data before ProcessKeyValue is called. The pre-loader would be responsible for parallelization of KeyVault calls, and it would update the secret cache so that by the time ProcessKeyValue is invoked, it just reads from cache (no I/O in ProcessKeyValue). This would preserve the precedence order for config composition. Other adapters dont have anything to preload, so they are no-op.

Task PreloadAsync(IEnumerable<ConfigurationSetting> settings, Logger logger, CancellationToken cancellationToken);

Semantics: "Given all the settings about to be processed, pre-warm your caches so that ProcessKeyValue can return instantly."

@linglingye001
linglingye001 merged commit 6ee5a65 into main Jul 24, 2026
2 checks passed
@linglingye001
linglingye001 deleted the linglingye/resolve-secret-parallel branch July 24, 2026 04:21
This was referenced Aug 1, 2026
Ole Jørgen Skogstad (oskogstad) added a commit to Altinn/dialogporten that referenced this pull request Aug 11, 2026
This PR contains the following updates:

| Package | Change |
[Age](https://docs.renovatebot.com/merge-confidence/) |
[Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
|
[Microsoft.Azure.AppConfiguration.AspNetCore](https://redirect.github.com/Azure/AppConfiguration)
([source](https://redirect.github.com/Azure/Azconfig-DotnetProvider)) |
`8.5.0` → `8.6.0` |
![age](https://developer.mend.io/api/mc/badges/age/nuget/Microsoft.Azure.AppConfiguration.AspNetCore/8.6.0?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/nuget/Microsoft.Azure.AppConfiguration.AspNetCore/8.5.0/8.6.0?slim=true)
|
| [Microsoft.OpenApi](https://redirect.github.com/Microsoft/OpenAPI.NET)
| `2.7.5` → `2.11.0` |
![age](https://developer.mend.io/api/mc/badges/age/nuget/Microsoft.OpenApi/2.11.0?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/nuget/Microsoft.OpenApi/2.7.5/2.11.0?slim=true)
|

---

### Release Notes

<details>
<summary>Azure/Azconfig-DotnetProvider
(Microsoft.Azure.AppConfiguration.AspNetCore)</summary>

###
[`v8.6.0`](https://redirect.github.com/Azure/AppConfiguration-DotnetProvider/releases/tag/8.6.0)

[Compare
Source](https://redirect.github.com/Azure/Azconfig-DotnetProvider/compare/8.5.0...8.6.0)

#### What's Changed

- Add null check in examples by
[@&#8203;linglingye001](https://redirect.github.com/linglingye001) in
[Azure/AppConfiguration-DotnetProvider#732](https://redirect.github.com/Azure/AppConfiguration-DotnetProvider/pull/732)
- Resolve key vault references concurrently by
[@&#8203;linglingye001](https://redirect.github.com/linglingye001) in
[Azure/AppConfiguration-DotnetProvider#736](https://redirect.github.com/Azure/AppConfiguration-DotnetProvider/pull/736)
- Upgrade package version by
[@&#8203;linglingye001](https://redirect.github.com/linglingye001) in
[Azure/AppConfiguration-DotnetProvider#745](https://redirect.github.com/Azure/AppConfiguration-DotnetProvider/pull/745)
- Version bump 8.6.0 by
[@&#8203;linglingye001](https://redirect.github.com/linglingye001) in
[Azure/AppConfiguration-DotnetProvider#746](https://redirect.github.com/Azure/AppConfiguration-DotnetProvider/pull/746)
- Migrate CI pipeline to ADO by
[@&#8203;zhiyuanliang-ms](https://redirect.github.com/zhiyuanliang-ms)
in
[Azure/AppConfiguration-DotnetProvider#750](https://redirect.github.com/Azure/AppConfiguration-DotnetProvider/pull/750)

**Full Changelog**:
<Azure/AppConfiguration-DotnetProvider@8.5.0...8.6.0>

</details>

<details>
<summary>Microsoft/OpenAPI.NET (Microsoft.OpenApi)</summary>

###
[`v2.11.0`](https://redirect.github.com/microsoft/OpenAPI.NET/releases/tag/v2.11.0)

##### Features

- adds support for anchor and id external resolution
([557bd6a](https://redirect.github.com/microsoft/OpenAPI.NET/commit/557bd6a8ca81e80f9f305aca3396e0e2fb45c09d))
- adds support for anchor and id external resolution
([4138e47](https://redirect.github.com/microsoft/OpenAPI.NET/commit/4138e478cc6e8ceb9d371ac3a4848887c80ec16f))
- **schema:** resolve bare $dynamicRef via $dynamicAnchor index
([#&#8203;2913](https://redirect.github.com/microsoft/OpenAPI.NET/issues/2913))
([baf8428](https://redirect.github.com/microsoft/OpenAPI.NET/commit/baf8428f488b0f1de8cb91b29c4f073f808f2ffe))
- **schema:** resolve bare $dynamicRef via $dynamicAnchor index
([#&#8203;2913](https://redirect.github.com/microsoft/OpenAPI.NET/issues/2913))
([a139f83](https://redirect.github.com/microsoft/OpenAPI.NET/commit/a139f83981b251315b55ad9a4d64756a5dead335))
- support relative URI resolution in $dynamicRef
([#&#8203;2928](https://redirect.github.com/microsoft/OpenAPI.NET/issues/2928))
([#&#8203;2945](https://redirect.github.com/microsoft/OpenAPI.NET/issues/2945))
([6091f5a](https://redirect.github.com/microsoft/OpenAPI.NET/commit/6091f5a799711f822f864ed67995cd518fd30e2e))
- support relative URI resolution in $dynamicRef
([#&#8203;2928](https://redirect.github.com/microsoft/OpenAPI.NET/issues/2928))
([#&#8203;2945](https://redirect.github.com/microsoft/OpenAPI.NET/issues/2945))
([a8688dc](https://redirect.github.com/microsoft/OpenAPI.NET/commit/a8688dc59ab69060e5413e5ac2f15430bd96e40f))

##### Bug Fixes

- adds explicit error message for invalid json pointers
([#&#8203;2955](https://redirect.github.com/microsoft/OpenAPI.NET/issues/2955))
([a304e56](https://redirect.github.com/microsoft/OpenAPI.NET/commit/a304e5646f4ccec388892238ce475945eb2af1b8))
- differentiate unset value from null value in OpenApiSchema.Const
([#&#8203;2936](https://redirect.github.com/microsoft/OpenAPI.NET/issues/2936))
([a8787af](https://redirect.github.com/microsoft/OpenAPI.NET/commit/a8787af57769821ee963be773be0b984a5078402))
- differentiate unset value from null value in OpenApiSchema.Const
([#&#8203;2936](https://redirect.github.com/microsoft/OpenAPI.NET/issues/2936))
([e08570f](https://redirect.github.com/microsoft/OpenAPI.NET/commit/e08570f99174b22e33775920212e478aac14df7c))
- handle nullability more accurately during serialization for 3.0/2.0
([#&#8203;2933](https://redirect.github.com/microsoft/OpenAPI.NET/issues/2933))
([bc11356](https://redirect.github.com/microsoft/OpenAPI.NET/commit/bc113563d174e6a6b1220b7e58f3b1c12e5a3f6f))
- handle nullability more accurately during serialization for 3.0/2.0
([#&#8203;2933](https://redirect.github.com/microsoft/OpenAPI.NET/issues/2933))
([310b6e2](https://redirect.github.com/microsoft/OpenAPI.NET/commit/310b6e29b3a17615efd7a38bbf5f73427cdec6e8))

###
[`v2.10.0`](https://redirect.github.com/microsoft/OpenAPI.NET/releases/tag/v2.10.0)

##### Features

- add JsonConverter for OpenApiSchema System.Text.Json serialization
([#&#8203;2915](https://redirect.github.com/microsoft/OpenAPI.NET/issues/2915))
([465521b](https://redirect.github.com/microsoft/OpenAPI.NET/commit/465521ba723ea9377d6838395d58e7212d64ece7))
- **library:** support schema keywords on references
([2749463](https://redirect.github.com/microsoft/OpenAPI.NET/commit/2749463f1ec1d452ba2334876d32466ea45ee8d1)),
closes
[#&#8203;2903](https://redirect.github.com/microsoft/OpenAPI.NET/issues/2903)

##### Bug Fixes

- Don't silently skip null assignment to OpenApiDocument.Tags
([#&#8203;2917](https://redirect.github.com/microsoft/OpenAPI.NET/issues/2917))
([6a45a82](https://redirect.github.com/microsoft/OpenAPI.NET/commit/6a45a826e095d198605b340c50d46c066eed72ad))
- handling of nullable enums for 3.0
([#&#8203;2920](https://redirect.github.com/microsoft/OpenAPI.NET/issues/2920))
([f4778e0](https://redirect.github.com/microsoft/OpenAPI.NET/commit/f4778e024e6bf033a4b6c4b90ea6636de712f826))
- **library:** keep v3 schema references ref-only
([8d811c3](https://redirect.github.com/microsoft/OpenAPI.NET/commit/8d811c3e76a8963be6e7a605b80c98d0ea0c63a5))
- preserve JSON Schema 2020-12 keyword siblings on $ref schemas for OAS
3.1+
([#&#8203;2896](https://redirect.github.com/microsoft/OpenAPI.NET/issues/2896))
([fb20d46](https://redirect.github.com/microsoft/OpenAPI.NET/commit/fb20d460ffe95505847da5a6e4c6fc065e41d9d1))
- preserve JSON Schema 2020-12 keyword siblings on $ref schemas for OAS
3.1+
([#&#8203;2896](https://redirect.github.com/microsoft/OpenAPI.NET/issues/2896))
([c79a83e](https://redirect.github.com/microsoft/OpenAPI.NET/commit/c79a83e74a0a41367c37f050d78d3e0ace838bc0))
- use async method for crypto flush
([677b519](https://redirect.github.com/microsoft/OpenAPI.NET/commit/677b5197d9c4f7de2122852ad49d5012f7082e71))

###
[`v2.9.0`](https://redirect.github.com/microsoft/OpenAPI.NET/releases/tag/v2.9.0)

##### Features

- add contains/minContains/maxContains members
([fadb422](https://redirect.github.com/microsoft/OpenAPI.NET/commit/fadb42225561e150aa99459c0c359c00cf52fb1a))
- **library:** add missing json schema properties
([db41a3c](https://redirect.github.com/microsoft/OpenAPI.NET/commit/db41a3c952e651f80a6bbdb7d8aac001031e6dd3))

##### Bug Fixes

- **library:** always copy unevaluated properties
([3951a31](https://redirect.github.com/microsoft/OpenAPI.NET/commit/3951a310da6056fd7a6852fda129a8ad8583639a))
- **library:** avoid false circular refs for external schema re-exports
([a058913](https://redirect.github.com/microsoft/OpenAPI.NET/commit/a058913943d4c197ccf03742f1c67ecc50e11a03))
- **library:** avoid false circular refs for external schema re-exports
([1bace68](https://redirect.github.com/microsoft/OpenAPI.NET/commit/1bace6804bc15c22b7665df7c66bed2a4a27bad0))
- **library:** merge contains compat members into missing properties
([7dc45e1](https://redirect.github.com/microsoft/OpenAPI.NET/commit/7dc45e14160825f79d5e64e6c9c8ba2a02900bcf))
- **library:** remove unshipped schema extension fallback
([b301827](https://redirect.github.com/microsoft/OpenAPI.NET/commit/b30182773fd875fb0a55c1a2bf48018910922ead))
- **library:** use version-specific schema keyword callbacks
([f93d76a](https://redirect.github.com/microsoft/OpenAPI.NET/commit/f93d76a4643022fc5d35b3d8ca8078276bbcce4f))
- **library:** use x-jsonschema schema extensions
([ec04a7f](https://redirect.github.com/microsoft/OpenAPI.NET/commit/ec04a7fcd43c296602edc15c197dc49cee112472))

###
[`v2.8.0`](https://redirect.github.com/microsoft/OpenAPI.NET/releases/tag/v2.8.0)

##### Features

- **reader:** remove ParseNode infrastructure
([d7c6a9d](https://redirect.github.com/microsoft/OpenAPI.NET/commit/d7c6a9dbe2da8cccac2a3dcbc5277bf0f20b0aa9))
- Significant performance improvements resulting \~40% reduced
allocations when parsing JSON descriptions, \~25% for YAML.

###
[`v2.7.6`](https://redirect.github.com/microsoft/OpenAPI.NET/releases/tag/v2.7.6)

##### Bug Fixes

- **reader:** preserve nullable Null flag when type appears after
nullable in V3.1/V3.2 deserializers
([288e95a](https://redirect.github.com/microsoft/OpenAPI.NET/commit/288e95aa743cb98dc69b44577ae78956f3f1c7c4))

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - "before 7am on Sunday,before 7am on Wednesday"
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR is behind base branch, or you tick the
rebase/retry checkbox.

👻 **Immortal**: This PR will be recreated if closed unmerged. Get
[config
help](https://redirect.github.com/renovatebot/renovate/discussions) if
that's undesired.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/Altinn/dialogporten).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4xMi4wIiwidXBkYXRlZEluVmVyIjoiNDQuMTIuMCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Ole Jørgen Skogstad <skogstad@softis.net>
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.

4 participants