Skip to content

fix: retry the PDP decision request once when it fails with a network error or 502, 503 or 504 - #1901

Open
Bjarnisan wants to merge 3 commits into
Altinn:mainfrom
Bjarnisan:fix/retry-pdp-decision
Open

Bjarnisan wants to merge 3 commits into
Altinn:mainfrom
Bjarnisan:fix/retry-pdp-decision

Conversation

@Bjarnisan

@Bjarnisan Bjarnisan commented Oct 22, 2026 •

Copy link
Copy Markdown

When the call to the authorization PDP fails at the network level, or the PDP answers 502, 503 or 504, PDPAppSI returns null and the user's request fails: a data save with 500, and opening or creating an instance with 403. Nothing retries the call, and the next request a moment later usually goes through. The issue has the numbers from our apps.

PdpRetryDelegatingHandler sends the request once more in those cases. It is added to the AuthorizationApiClient registration in AddAltinnAppServices, so it covers every call through IPDP: AppAccessHandler, AuthorizationClient, InstancesController and StatelessDataController.

  • Only HttpRequestException and 502, 503 and 504 are retried, once and without delay. Other status codes, 500 and 429 included, pass through unchanged. A canceled request is not sent again, also when it is canceled after the first attempt failed. HttpClient.Timeout covers both attempts.
  • The decision request is safe to repeat. When the first attempt reached the PDP before the connection failed, the PDP logs one more audit event for it.
  • The retry runs inside the same request, before the app reads the instance. A save that is retried after the instance was submitted from another client gets 409 "Instance Not Active", as any slow save does today.
  • If the PDP is down, each failed call is sent twice. Calls that succeed are sent once.
  • The handler is internal and created with a factory, like MaskinportenDelegatingHandler, so the public API is unchanged and there is no new dependency. Each attempt gets its own HTTP client activity, and a retry logs one warning. Both attempts send the same traceparent, since DiagnosticsHandler only adds trace headers that are missing, so the PDP's telemetry links a retried call to the first attempt, in the same trace.

This does not change what happens after two failures in a row: the request fails as before. In the TLS case the user still waits about 26 seconds before the second attempt. v9 has the same registration (src/App/backend/src/Altinn.App.Api/Extensions/ServiceCollectionExtensions.cs in altinn-studio), and I can open a PR there too if you want this.

Related Issue(s)

Verification

  • Your code builds clean without any errors or warnings
  • Manual testing done (required)
  • Relevant automated test added (if you find this hard, leave it and we'll help out)
  • All tests run green

PdpRetryDelegatingHandlerTests has 17 cases: a retry after 502, 503, 504 and HttpRequestException with the same body sent twice, the first response disposed, two failures in a row, no retry for 200, 400, 401, 403, 404 and 500, no retry when the request is canceled before or after the first attempt, and no attempt still running when SendAsync returns. ServiceCollectionExtensionsTests builds the app with AppBuilder and checks that an AuthorizationApiClient from DI gets the decision after one failed attempt. Removing the registration, the status code check, the retry after HttpRequestException, response.Dispose() or the cancellation check, counting 500 as transient, catching every exception, or sending the retry without awaiting it each makes at least one test fail. Coverlet shows every changed line and branch in src covered. Core and Api tests pass on net8.0 and net10.0, and CI=true dotnet build solutions/All.sln gives no code warnings.

Manual test in localtest with two of our apps and a small TCP proxy in front of the PDP that resets the connection, answers 503, or holds a request and then resets it, on demand. On Altinn.App 8.12.11 and on main, one reset gave 500 on a data save, 403 when opening the instance and 403 when creating a new one, and one 503 gave 500 on a save. With this branch all four went through, and the log showed one "Request to PDP failed, retrying once" or "PDP returned 503, retrying once" per failure. Two resets in a row still gave 500, and the next save went through. With a save held for 6 seconds while a second client saved and submitted the instance, the held save got 409 after its retry, and the submitted data was unchanged.

Documentation

  • User documentation is updated with a separate linked PR in altinn-studio-docs. (if applicable)

…03 and 504

AppAccessHandler and the other PEP callers get null from PDPAppSI when the
call to the authorization decision endpoint fails, and the request then ends
in 500 (data save) or 403 (opening or creating an instance), although the next
request a moment later goes through.

PdpRetryDelegatingHandler sends the request once more on HttpRequestException
or a 502, 503 or 504 response. A decision request only asks a question, so
sending it twice changes nothing. Cancellation and other status codes are not
retried.
…response is disposed, and create the handler with a factory
…t no attempt is left running when SendAsync returns
@coderabbitai

coderabbitai Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 664af737-f8e2-4233-aa27-03826b7dc7d5
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@Bjarnisan

Copy link
Copy Markdown
Author

Could someone approve the workflow runs and add the bugfix label for the Label Check? Thanks!

@Bjarnisan
Bjarnisan force-pushed the fix/retry-pdp-decision branch from 2ce3b0f to 79ef708 Compare October 30, 2026 08:05

This branch has not been deployed

No deployments
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.

A single network error towards the PDP fails the request with 500 or 403

1 participant