Skip to content

fix(parameters): recover AppConfig sessions after rejected poll tokens - #8615

Merged
leandrodamascena merged 3 commits into
aws-powertools:developfrom
proton0210:fix/8589-appconfig-token-recovery
Oct 22, 2026
Merged

leandrodamascena merged 3 commits into
aws-powertools:developfrom
proton0210:fix/8589-appconfig-token-recovery

Conversation

@proton0210

Copy link
Copy Markdown
Contributor

Issue number: closes #8589

Summary

Changes

  • Restart the AppConfig configuration session and retry retrieval once when GetLatestConfiguration rejects its poll token with BadRequestException.
  • Discard rejected tokens, including a rejected replacement, so a later call can start a fresh session. Initial session-creation errors and unrelated service failures do not trigger token recovery.
  • Invalidate the affected session token if the response body cannot be read completely. Starting a new session on the next retrieval avoids reusing a consumed token or missing the configuration that failed to arrive.
  • Keep recovery scoped to the requested configuration and preserve caching, transformations, SDK session options, and the last successfully returned value.
  • Document the behavior in the provider's API docstring and add 11 functional regressions using real boto3 clients with botocore Stubber. No dependency changes.

User experience

Before: after a poll token is rejected, a warm environment keeps sending that same token and failing until a cold start. A response-body failure can strand it in the same way.

After: a rejected poll token gets one session restart and retry. A second rejection raises GetParameterError without looping, and a later retrieval can recover. Body-read failures still surface as GetParameterError and allow a fresh session next time. Other service errors retain their existing behavior; recovery never silently returns a stale value in place of an error.

Verification

  • Regression-first: all three initial tests failed against the original provider, demonstrating rejected-token reuse, missing bounded recovery, and consumed-token reuse after a truncated response (the unconsumed expected responses also caused two Stubber teardown errors).
  • Parameters functional suite: 149 passed, with 100% statement and branch coverage for appconfig.py.
  • New recovery suite on Python 3.10: 11 passed. Main validation uses Python 3.13; the remaining supported versions were not run locally.
  • Full make pr passes: 3,784 passed, 73 skipped, 10 deselected, followed by 10 passing performance tests, with 96.95% overall coverage. This includes Ruff, documentation lint, mypy (943 source files), normal pre-commit checks, security baseline and complexity baseline. The additional ty check passes.
  • Isolated SDK-only Nox session: 559 passed, 2 deselected, verifying required dependencies independently of optional validation/parser extras.
  • Source distribution and wheel build successfully with uv build --no-sources.
  • Three audit passes: issue/root-cause and failing regressions; bounded retry, profile isolation, cache/error semantics and token handling; final diff, locked-tooling checks, package build and regression review.

All AppConfig interactions were stubbed. No AWS resources were created, no live AppConfig calls were made, and no configuration tokens or credentials were logged. Full-suite networking was restricted to loopback services and the public OpenAPI schema host used by existing tests.


By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

@proton0210
proton0210 requested a review from a team as a code owner October 18, 2026 16:54
@proton0210
proton0210 requested a review from svozza October 18, 2026 16:54
@boring-cyborg

boring-cyborg Bot commented Oct 18, 2026

Copy link
Copy Markdown

Thanks a lot for your first contribution! Please check out our contributing guidelines and don't hesitate to ask whatever you need.
In the meantime, check out the #python channel on our Powertools for AWS Lambda Discord: Invite link

@leandrodamascena leandrodamascena 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 @proton0210, this is solid work and the tests are thorough. I ran it against a real AppConfig deployment though, and there's one case we need to handle differently. BadRequestException isn't only "token expired": with RequiredMinimumPollIntervalInSeconds set, polling too early also returns it, with Details.InvalidParameters.ConfigurationToken.Problem == "PollIntervalNotSatisfied" and the token stays valid (I polled again with the same token 15 s later and it worked). With this PR that case starts a new session and fetches right away, so we end up bypassing the interval the user asked for, 3 API calls instead of an error.

Could you restart the session only when Problem is Expired or Corrupted, and keep today's behavior (keep the token, raise) for PollIntervalNotSatisfied? The error details are in exc.response["Details"], and the Stubber can simulate them via modeled_fields. Everything else looked right to me: unrelated errors don't retry, sdk_options carry over to the new session, empty bodies still return the last value.

@leandrodamascena leandrodamascena 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 @proton0210, that's exactly it. I re-ran it against real AppConfig with a 15 s poll interval: polling too early now raises and keeps the token, the same token works after the interval with no extra session, and an injected corrupted token recovers in one call. The Problem lookup is clean and the docstring says what it does.

Approving now. This goes out in 3.38.0, so it will sit here a bit before I merge. No need to rebase or touch anything, I'll take care of it and you'll get the credit in the release notes. Thank you!

@proton0210
proton0210 marked this pull request as draft October 21, 2026 06:07
@proton0210
proton0210 marked this pull request as ready for review October 21, 2026 06:09
proton0210 and others added 3 commits October 22, 2026 14:39
Since aws-powertools#8619 sdk_options are part of the cache key, so the cached read must pass the same RequiredMinimumPollIntervalInSeconds option as the call that populated it.

@leandrodamascena leandrodamascena 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.

Rebased on develop and adjusted one test line: since #8619 the sdk_options are part of the cache key, so the cached read has to pass the same RequiredMinimumPollIntervalInSeconds as the call that populated it. Your code is untouched, suite green locally. Re-approving.

@sonarqubecloud

Copy link
Copy Markdown

@codecov

codecov Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 96.95%. Comparing base (050aba6) to head (c0a4cdc).

Additional details and impacted files
@@             Coverage Diff             @@
##           develop    #8615      +/-   ##
===========================================
+ Coverage    96.93%   96.95%   +0.01%     
===========================================
  Files          318      318              
  Lines        16076    16103      +27     
  Branches      1436     1440       +4     
===========================================
+ Hits         15584    15613      +29     
  Misses         349      349              
+ Partials       143      141       -2     

☔ 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.

@leandrodamascena
leandrodamascena merged commit c14bb80 into aws-powertools:develop Oct 22, 2026
14 checks passed
@powertools-for-aws-oss-automation

Copy link
Copy Markdown

Awesome work, congrats on your first merged pull request and thank you for helping improve everyone's experience!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/L Denotes a PR that changes 100-499 lines, ignoring generated files. tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: AppConfigProvider never recovers after get_latest_configuration rejects the poll token

2 participants