Skip to content

feat: adding circuit breaker feature#8266

Open
leandrodamascena wants to merge 3 commits into
developfrom
feat/circuit-breaker
Open

feat: adding circuit breaker feature#8266
leandrodamascena wants to merge 3 commits into
developfrom
feat/circuit-breaker

Conversation

@leandrodamascena

Copy link
Copy Markdown
Contributor

Issue number: closes #8257

Summary

Changes

This PR adds a Circuit Breaker utility (under the circuit_breaker_alpha namespace) so a Lambda function can stop calling an unhealthy downstream and let it recover, instead of piling on retries.

It ships as alpha on purpose: I want about a month of feedback before we lock the public API and promote it to GA.

The failure counter lives in memory per execution environment, so a healthy circuit writes nothing; we only persist state transitions. State is shared via DynamoDB, fails open if the store is unreachable, and uses a conditional write to elect a single probe during recovery (no thundering herd). You handle rejected requests with an on_circuit_open callback and observe state changes with an on_transition hook.

User experience

Before, you had to build the state machine, shared storage, and recovery logic yourself. Now you wrap the function that makes the downstream call:

from aws_lambda_powertools.utilities.circuit_breaker_alpha import circuit_breaker
from aws_lambda_powertools.utilities.circuit_breaker_alpha.persistence import (
    CircuitBreakerDynamoDBPersistence,
)

persistence = CircuitBreakerDynamoDBPersistence(table_name="CircuitBreakerState")


@circuit_breaker(name="payment-backend", persistence_store=persistence)
def charge(order: dict) -> dict:
    return payment_api.charge(order)

With no config, sensible defaults apply (open after 5 failures, probe after 30s, close after 3 successes). When open, the call is skipped and the callback's value is returned, or a CircuitBreakerOpenError is raised.


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

Disclaimer: We value your time and bandwidth. As such, any pull requests created on non-triaged issues might not be successful.

@leandrodamascena leandrodamascena requested a review from a team as a code owner June 9, 2026 21:15
@leandrodamascena leandrodamascena requested a review from hjgraca June 9, 2026 21:15
@boring-cyborg boring-cyborg Bot added commons documentation Improvements or additions to documentation tests labels Jun 9, 2026
@powertools-for-aws-oss-automation powertools-for-aws-oss-automation Bot added the size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. label Jun 9, 2026
@powertools-for-aws-oss-automation powertools-for-aws-oss-automation Bot added size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. and removed size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. labels Jun 9, 2026
return cached

try:
record = self._get_record(name)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does _get_record really need to throw an exception here? Can we not just check if the value returned is `None?

opened_at=opened_at,
expiry_timestamp=self._durable_ttl(),
)
self._update_record(record)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if this fails? Does it leave the DynamoDB row permanently stale?

raise

def _update_record(self, record: CircuitStateRecord) -> None:
update_expression = "SET #state = :state, #failure_count = :failure_count"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this query creation logic could be a separate private method

@powertools-for-aws-oss-automation powertools-for-aws-oss-automation Bot added size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. and removed size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. labels Jun 10, 2026
@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
C Reliability Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

@codecov

codecov Bot commented Jun 10, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 93.48442% with 23 lines in your changes missing coverage. Please review.
✅ Project coverage is 96.64%. Comparing base (683ba5f) to head (0c991ea).

Files with missing lines Patch % Lines
...ties/circuit_breaker_alpha/persistence/dynamodb.py 84.41% 7 Missing and 5 partials ⚠️
...powertools/utilities/circuit_breaker_alpha/base.py 94.31% 2 Missing and 3 partials ⚠️
...tilities/circuit_breaker_alpha/persistence/base.py 94.87% 2 Missing and 2 partials ⚠️
...ools/utilities/circuit_breaker_alpha/exceptions.py 87.50% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           develop    #8266      +/-   ##
===========================================
- Coverage    96.72%   96.64%   -0.08%     
===========================================
  Files          286      296      +10     
  Lines        14347    14700     +353     
  Branches      1201     1231      +30     
===========================================
+ Hits         13877    14207     +330     
- Misses         341      353      +12     
- Partials       129      140      +11     

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

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

Labels

commons documentation Improvements or additions to documentation size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

RFC: Circuit Breaker with Fallback

2 participants