Skip to content

feat: add Microservices Load Shedding pattern (#3229) - #3599

Open
ylcn91 wants to merge 1 commit into
iluwatar:masterfrom
ylcn91:feat/microservices-load-shedding
Open

feat: add Microservices Load Shedding pattern (#3229)#3599
ylcn91 wants to merge 1 commit into
iluwatar:masterfrom
ylcn91:feat/microservices-load-shedding

Conversation

@ylcn91

@ylcn91 ylcn91 commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

Adds the Microservices Load Shedding pattern as a new microservices-load-shedding module.

  • Problem: under a traffic spike or a slow dependency, requests pile up, latency grows for everyone and the service eventually falls over.
  • Solution: a LoadShedder performs capacity-based, priority-aware admission control at the service entry point. Excess requests are rejected immediately (fail fast) instead of being queued; low-priority work is shed first and a reserve of capacity is kept for critical requests.
  • Key components:
    • Priority, Request, Response: the request model with CRITICAL / NORMAL / LOW priorities.
    • LoadShedder: hard capacity, low-priority limit and critical reserve; lock-free compare-and-set admission so capacity is never exceeded; per-priority shed counters.
    • LoadShedException: the fast rejection ("503, retry later").
    • ShedGuardedService and RequestHandler: wrap the business logic and always release the capacity slot, even when the handler throws.
    • App: light load (everything admitted), payment provider slows down and orders pile up (LOW and NORMAL probes are shed, CRITICAL checkout still admitted), provider recovers (admission resumes), then a metrics summary. Logging traces every decision.
    • README.md: intent, real-world example, flowchart, code walkthrough, applicability, trade-offs, and how load shedding differs from rate limiting, throttling, backpressure and queue-based load leveling. PlantUML class diagram under etc/.
  • Tests: 13 JUnit 5 tests covering admission below capacity, priority-ordered shedding, the critical reserve, release, metrics, a 50-thread concurrency test proving capacity is never exceeded, slot release on handler failure, plus AppTest.
  • Module registered in the parent pom.xml. ./mvnw clean verify -pl microservices-load-shedding passes locally on JDK 21 and inside an eclipse-temurin:21 container.

Fixes #3229

@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown

PR Summary

Introduces a new microservices-load-shedding module implementing the Load Shedding pattern with capacity-based admission control and prioritization. The module provides Priority, Request, Response, LoadShedder, LoadShedException, ShedGuardedService, and a runnable App demo, plus unit tests (AppTest, LoadShedderTest, ShedGuardedServiceTest). Includes documentation (README), a PlantUML diagram, and a module POM. The root pom.xml is updated to include this module.

Changes

File Summary
microservices-load-shedding/README.md Documentation for the Load Shedding pattern in Java, covering intent, real-world examples, flow, and how shedding differs from rate limiting and backpressure, with a runnable example, class diagram reference and trade-offs.
microservices-load-shedding/etc/microservices-load-shedding.urm.puml PlantUML class diagram describing the core classes and relationships of the Load Shedding pattern.
microservices-load-shedding/pom.xml Module POM for microservices-load-shedding, declaring dependencies (slf4j/logback/junit) and build setup, and assembly plugin entry for a runnable main class.
microservices-load-shedding/src/main/java/com/iluwatar/loadshedding/App.java Demo application orchestrating the Load Shedder with a guarded service, simulating phases of light load, shedding due to a slow dependency, and recovery, with logging.
microservices-load-shedding/src/main/java/com/iluwatar/loadshedding/LoadShedException.java Exception type thrown when admission is refused by the LoadShedder; carries request id and priority.
microservices-load-shedding/src/main/java/com/iluwatar/loadshedding/LoadShedder.java Core admission controller implementing capacity-based, priority-aware shedding with atomic in-flight tracking and per-priority shed counters.
microservices-load-shedding/src/main/java/com/iluwatar/loadshedding/Priority.java Priority enum with CRITICAL, NORMAL, and LOW for shedding decisions.
microservices-load-shedding/src/main/java/com/iluwatar/loadshedding/Request.java Request data model carrying id, priority, and description.
microservices-load-shedding/src/main/java/com/iluwatar/loadshedding/RequestHandler.java Functional interface representing the business logic to execute for admitted requests.
microservices-load-shedding/src/main/java/com/iluwatar/loadshedding/Response.java Response model with ACCEPTED/REJECTED statuses and helper factories for accepted and rejected responses.
microservices-load-shedding/src/main/java/com/iluwatar/loadshedding/ShedGuardedService.java Guarded service using LoadShedder to gate admission and ensuring capacity release after processing.
microservices-load-shedding/src/test/java/com/iluwatar/loadshedding/AppTest.java Unit tests for App behaviors and utilities (e.g., simulated payment provider, result collection, and shutdown helpers).
microservices-load-shedding/src/test/java/com/iluwatar/loadshedding/LoadShedderTest.java Unit tests for LoadShedder's admission strategy, shedding counters, boundary config, and concurrency behavior.
microservices-load-shedding/src/test/java/com/iluwatar/loadshedding/ShedGuardedServiceTest.java Unit tests for ShedGuardedService paths: admitted handling, shed paths, and capacity release when handlers fail.
modified: pom.xml Root pom.xml updated to declare the new module microservices-load-shedding in the modules list.

autogenerated by presubmit.ai

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🚨 Pull request needs attention.

Review Summary

Commits Considered (1)
  • 50b5af8: feat: add Microservices Load Shedding pattern (#3229)
Files Processed (15)
  • microservices-load-shedding/README.md (1 hunk)
  • microservices-load-shedding/etc/microservices-load-shedding.urm.puml (1 hunk)
  • microservices-load-shedding/pom.xml (1 hunk)
  • microservices-load-shedding/src/main/java/com/iluwatar/loadshedding/App.java (1 hunk)
  • microservices-load-shedding/src/main/java/com/iluwatar/loadshedding/LoadShedException.java (1 hunk)
  • microservices-load-shedding/src/main/java/com/iluwatar/loadshedding/LoadShedder.java (1 hunk)
  • microservices-load-shedding/src/main/java/com/iluwatar/loadshedding/Priority.java (1 hunk)
  • microservices-load-shedding/src/main/java/com/iluwatar/loadshedding/Request.java (1 hunk)
  • microservices-load-shedding/src/main/java/com/iluwatar/loadshedding/RequestHandler.java (1 hunk)
  • microservices-load-shedding/src/main/java/com/iluwatar/loadshedding/Response.java (1 hunk)
  • microservices-load-shedding/src/main/java/com/iluwatar/loadshedding/ShedGuardedService.java (1 hunk)
  • microservices-load-shedding/src/test/java/com/iluwatar/loadshedding/AppTest.java (1 hunk)
  • microservices-load-shedding/src/test/java/com/iluwatar/loadshedding/LoadShedderTest.java (1 hunk)
  • microservices-load-shedding/src/test/java/com/iluwatar/loadshedding/ShedGuardedServiceTest.java (1 hunk)
  • pom.xml (1 hunk)
Actionable Comments (2)
  • microservices-load-shedding/src/main/java/com/iluwatar/loadshedding/App.java [88-93]

    possible bug: "Logger field name mismatch with Lombok annotation"

  • microservices-load-shedding/src/main/java/com/iluwatar/loadshedding/ShedGuardedService.java [68-74]

    possible bug: "Logger usage should use generated logger name (admission log)"

Skipped Comments (1)
  • pom.xml [263-263]

    enhancement: "Module wiring: add microservices-load-shedding"

Comment on lines +88 to +93
LOGGER.info(
"Order service capacity: {} in flight, low priority shed at {}, {} slot reserved for"
+ " critical requests",
CAPACITY,
LOW_PRIORITY_LIMIT,
CRITICAL_RESERVE);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Logger field name mismatch with Lombok @slf4j annotation. Lombok generates a 'log' field (not 'LOGGER') when using @slf4j. This code uses LOGGER, which will fail to compile. Replace LOGGER with log (or switch to a logger field name that matches the generated one).

Comment on lines +68 to +74
LOGGER.info(
"[{}] admitted {} ({}), {}/{} in flight",
name,
request.id(),
request.priority(),
shedder.getInFlight(),
shedder.getMaxInFlight());

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Similar issue as above for the admission log path. Replace LOGGER.info with log.info to ensure logging compiles and follows Lombok's generated logger name.

@ylcn91

ylcn91 commented Sep 3, 2026

Copy link
Copy Markdown
Contributor Author

Note on the automated review comments: LOGGER is the Lombok logger field name configured for this repository in lombok.config (lombok.log.fieldName = LOGGER), the same name every other module uses, so the code compiles as is. Local ./mvnw clean verify -pl microservices-load-shedding passes on JDK 21, also inside an eclipse-temurin:21 container.

@codecov

codecov Bot commented Sep 3, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 83.95%. Comparing base (41625d8) to head (c5ba691).

Additional details and impacted files
@@             Coverage Diff              @@
##             master    #3599      +/-   ##
============================================
+ Coverage     83.79%   83.95%   +0.16%     
- Complexity     4277     4322      +45     
============================================
  Files          1121     1128       +7     
  Lines         15144    15284     +140     
  Branches        723      732       +9     
============================================
+ Hits          12690    12832     +142     
+ Misses         2159     2157       -2     
  Partials        295      295              

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

@ylcn91
ylcn91 force-pushed the feat/microservices-load-shedding branch from 50b5af8 to 6d9f7e0 Compare September 3, 2026 09:52
@ylcn91

ylcn91 commented Sep 3, 2026

Copy link
Copy Markdown
Contributor Author

Follow-up on the Codecov note: completed the LoadShedder constructor validation cases (every branch of the three checks plus a boundary configuration) and added AppTest cases for the demo helpers' interruption and failed-worker paths, which are now package-private for testing. 19 tests. Remaining uncovered lines are the demo's five-second safety timeouts and the CAS retry branch, which cannot be forced deterministically. ./mvnw clean verify -pl microservices-load-shedding passes locally on JDK 21 and in an eclipse-temurin:21 container.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

LGTM!

Review Summary

Commits Considered (1)
  • 6d9f7e0: feat: add Microservices Load Shedding pattern (#3229)
Files Processed (15)
  • microservices-load-shedding/README.md (1 hunk)
  • microservices-load-shedding/etc/microservices-load-shedding.urm.puml (1 hunk)
  • microservices-load-shedding/pom.xml (1 hunk)
  • microservices-load-shedding/src/main/java/com/iluwatar/loadshedding/App.java (1 hunk)
  • microservices-load-shedding/src/main/java/com/iluwatar/loadshedding/LoadShedException.java (1 hunk)
  • microservices-load-shedding/src/main/java/com/iluwatar/loadshedding/LoadShedder.java (1 hunk)
  • microservices-load-shedding/src/main/java/com/iluwatar/loadshedding/Priority.java (1 hunk)
  • microservices-load-shedding/src/main/java/com/iluwatar/loadshedding/Request.java (1 hunk)
  • microservices-load-shedding/src/main/java/com/iluwatar/loadshedding/RequestHandler.java (1 hunk)
  • microservices-load-shedding/src/main/java/com/iluwatar/loadshedding/Response.java (1 hunk)
  • microservices-load-shedding/src/main/java/com/iluwatar/loadshedding/ShedGuardedService.java (1 hunk)
  • microservices-load-shedding/src/test/java/com/iluwatar/loadshedding/AppTest.java (1 hunk)
  • microservices-load-shedding/src/test/java/com/iluwatar/loadshedding/LoadShedderTest.java (1 hunk)
  • microservices-load-shedding/src/test/java/com/iluwatar/loadshedding/ShedGuardedServiceTest.java (1 hunk)
  • pom.xml (1 hunk)
Actionable Comments (0)
Skipped Comments (2)
  • microservices-load-shedding/src/main/java/com/iluwatar/loadshedding/App.java [87-94]

    bug: "Fix logger usage with Lombok @slf4j in App"

  • microservices-load-shedding/src/main/java/com/iluwatar/loadshedding/ShedGuardedService.java [65-75]

    bug: "Logger field name mismatch in ShedGuardedService"

@ylcn91
ylcn91 force-pushed the feat/microservices-load-shedding branch from 6d9f7e0 to c5ba691 Compare September 3, 2026 11:32
@ylcn91

ylcn91 commented Sep 3, 2026

Copy link
Copy Markdown
Contributor Author

Coverage follow-up: LoadShedder.acquire now uses AtomicInteger.getAndAccumulate with a pure accumulator instead of a hand-written compare-and-set loop, which is simpler and removes the untestable retry branch; the README snippet was updated to match. The demo helpers in App take a Duration so tests can exercise their timeout branches in milliseconds; main still uses the five-second value. JaCoCo now reports 100% instruction, branch and line coverage. Verified locally on JDK 21 and in an eclipse-temurin:21 container, five consecutive test runs, packaged jar runs end to end.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🚨 Pull request needs attention.

Review Summary

Commits Considered (1)
  • c5ba691: feat: add Microservices Load Shedding pattern (#3229)
Files Processed (15)
  • microservices-load-shedding/README.md (1 hunk)
  • microservices-load-shedding/etc/microservices-load-shedding.urm.puml (1 hunk)
  • microservices-load-shedding/pom.xml (1 hunk)
  • microservices-load-shedding/src/main/java/com/iluwatar/loadshedding/App.java (1 hunk)
  • microservices-load-shedding/src/main/java/com/iluwatar/loadshedding/LoadShedException.java (1 hunk)
  • microservices-load-shedding/src/main/java/com/iluwatar/loadshedding/LoadShedder.java (1 hunk)
  • microservices-load-shedding/src/main/java/com/iluwatar/loadshedding/Priority.java (1 hunk)
  • microservices-load-shedding/src/main/java/com/iluwatar/loadshedding/Request.java (1 hunk)
  • microservices-load-shedding/src/main/java/com/iluwatar/loadshedding/RequestHandler.java (1 hunk)
  • microservices-load-shedding/src/main/java/com/iluwatar/loadshedding/Response.java (1 hunk)
  • microservices-load-shedding/src/main/java/com/iluwatar/loadshedding/ShedGuardedService.java (1 hunk)
  • microservices-load-shedding/src/test/java/com/iluwatar/loadshedding/AppTest.java (1 hunk)
  • microservices-load-shedding/src/test/java/com/iluwatar/loadshedding/LoadShedderTest.java (1 hunk)
  • microservices-load-shedding/src/test/java/com/iluwatar/loadshedding/ShedGuardedServiceTest.java (1 hunk)
  • pom.xml (1 hunk)
Actionable Comments (2)
  • microservices-load-shedding/src/main/java/com/iluwatar/loadshedding/App.java [90-96]

    best_practice: "Logger name mismatch with Lombok @slf4j in App"

  • microservices-load-shedding/src/main/java/com/iluwatar/loadshedding/ShedGuardedService.java [68-75]

    best_practice: "Logger usage mismatch with Lombok @slf4j in ShedGuardedService (admission log)"

Skipped Comments (0)

Comment on lines +90 to +96
LOGGER.info(
"Order service capacity: {} in flight, low priority shed at {}, {} slot reserved for"
+ " critical requests",
CAPACITY,
LOW_PRIORITY_LIMIT,
CRITICAL_RESERVE);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Replace the Lombok-generated logger reference (log) instead of the plain 'LOGGER' used in this class. Lombok's @slf4j generates a 'log' field, not 'LOGGER'. This will fail to compile. Update all occurrences in this file to use 'log'.

Comment on lines +68 to +75
LOGGER.info(
"[{}] admitted {} ({}), {}/{} in flight",
name,
request.id(),
request.priority(),
shedder.getInFlight(),
shedder.getMaxInFlight());
try {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Similarly, replace the subsequent log statement that announces admission with the Lombok-provided logger (log) to ensure compile-time correctness.

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.

Implement Microservices Load Shedding pattern

1 participant