Background
Follow-up to #2276 / PR #2277, which shipped the delegated-rights export endpoint
(GET /accessmanagement/api/v1/delegationexport/reportee/{partyUuid}) as a quick fix.
The export iterates over each giver (main org + every underenhet) sequentially, and for
each giver fetches roles, access packages, single rights and instances. For an organization
with many underenheter this produces a long sequential chain of backend calls and can
increase response time / risk timeouts.
Flagged by CodeRabbit and the Copilot reviewer on PR #2277.
Why it wasn't done in the quick fix
A naive Task.WhenAll fan-out is not safe as-is: the underlying *Client implementations
(e.g. AccessPackageClient, RoleClient, SingleRightClient, InstanceClient) read the JWT
via JwtTokenUtil.GetTokenFromContext(_httpContextAccessor.HttpContext) on every call, and
HttpContext is not thread-safe for concurrent access. Parallelizing without addressing this
would introduce races on HttpContext.
Proposed work
- Capture the bearer token (and any other per-request context) once up front, before
fanning out, so worker tasks don't touch HttpContext concurrently. This likely means a
token/context-aware overload at the client or a small context-capture helper.
- Parallelize per-giver (and optionally per-type) with
Task.WhenAll, preserving deterministic
output order by mapping givers -> Task<List<row>> and flattening in order.
- Add an optional concurrency limit (e.g.
SemaphoreSlim) to avoid overloading downstream
services for orgs with very many underenheter.
- Ensure the underlying
HttpClient-based clients are otherwise thread-safe for concurrent use.
Acceptance criteria
Code refs
DelegationExportService.ExportReporteeDelegations / Build*Rows
backend/src/Altinn.AccessManagement.UI/Altinn.AccessManagement.UI.Integration/Clients/*Client.cs
🤖 Generated with Claude Code
Background
Follow-up to #2276 / PR #2277, which shipped the delegated-rights export endpoint
(
GET /accessmanagement/api/v1/delegationexport/reportee/{partyUuid}) as a quick fix.The export iterates over each giver (main org + every underenhet) sequentially, and for
each giver fetches roles, access packages, single rights and instances. For an organization
with many underenheter this produces a long sequential chain of backend calls and can
increase response time / risk timeouts.
Flagged by CodeRabbit and the Copilot reviewer on PR #2277.
Why it wasn't done in the quick fix
A naive
Task.WhenAllfan-out is not safe as-is: the underlying*Clientimplementations(e.g.
AccessPackageClient,RoleClient,SingleRightClient,InstanceClient) read the JWTvia
JwtTokenUtil.GetTokenFromContext(_httpContextAccessor.HttpContext)on every call, andHttpContextis not thread-safe for concurrent access. Parallelizing without addressing thiswould introduce races on
HttpContext.Proposed work
fanning out, so worker tasks don't touch
HttpContextconcurrently. This likely means atoken/context-aware overload at the client or a small context-capture helper.
Task.WhenAll, preserving deterministicoutput order by mapping
givers -> Task<List<row>>and flattening in order.SemaphoreSlim) to avoid overloading downstreamservices for orgs with very many underenheter.
HttpClient-based clients are otherwise thread-safe for concurrent use.Acceptance criteria
HttpContext.Code refs
DelegationExportService.ExportReporteeDelegations/Build*Rowsbackend/src/Altinn.AccessManagement.UI/Altinn.AccessManagement.UI.Integration/Clients/*Client.cs🤖 Generated with Claude Code