From 87fdf74fc5cac24c6b2fdbd96f514bb2501eb3f0 Mon Sep 17 00:00:00 2001 From: dyrpsf Date: Thu, 2 Oct 2025 12:03:45 +0530 Subject: [PATCH 1/2] Add Timeout pattern implementation - Fixes #2845 --- timeout/README.md | 101 ++++ timeout/etc/timeout.urm.png.png | Bin 0 -> 32627 bytes timeout/etc/timeout.urm.puml | 37 ++ timeout/pom.xml | 32 ++ .../main/java/com/iluwatar/timeout/App.java | 517 ++++++++++++++++++ .../iluwatar/timeout/TimeoutException.java | 15 + .../com/iluwatar/timeout/TimeoutHandler.java | 67 +++ .../iluwatar/timeout/TimeoutHandlerTest.java | 67 +++ 8 files changed, 836 insertions(+) create mode 100644 timeout/README.md create mode 100644 timeout/etc/timeout.urm.png.png create mode 100644 timeout/etc/timeout.urm.puml create mode 100644 timeout/pom.xml create mode 100644 timeout/src/main/java/com/iluwatar/timeout/App.java create mode 100644 timeout/src/main/java/com/iluwatar/timeout/TimeoutException.java create mode 100644 timeout/src/main/java/com/iluwatar/timeout/TimeoutHandler.java create mode 100644 timeout/src/test/java/com/iluwatar/timeout/TimeoutHandlerTest.java diff --git a/timeout/README.md b/timeout/README.md new file mode 100644 index 000000000000..d9fea83ba33e --- /dev/null +++ b/timeout/README.md @@ -0,0 +1,101 @@ +# Timeout Pattern + +## Intent +Prevent operations from blocking indefinitely by setting a maximum time limit for their completion. If the operation doesn't complete within the specified timeout period, it is cancelled and control is returned to the caller with an error. + +## Explanation + +Real-world example + +> Consider a restaurant where customers place orders. The kitchen has a policy that if a dish cannot be prepared within 30 minutes, the order is cancelled and the customer is notified. This prevents customers from waiting indefinitely and allows them to make alternative arrangements. + +In plain words + +> The Timeout pattern ensures that operations complete within a specified time limit, preventing indefinite blocking and improving system responsiveness. + +**Programmatic Example** + +The Timeout pattern is implemented using the `TimeoutHandler` class which wraps operations and enforces time constraints: + +```java +TimeoutHandler handler = new TimeoutHandler(); + +// Execute a task with 3 second timeout +try { + String result = handler.execute(() -> { + // Simulate some processing + Thread.sleep(1000); + return "Operation completed"; + }, 3, TimeUnit.SECONDS); + + System.out.println(result); +} catch (TimeoutException e) { + System.err.println("Operation timed out: " + e.getMessage()); +} +``` + +The `TimeoutHandler` uses an `ExecutorService` to run tasks asynchronously and monitors their completion: + +```java +public T execute(Callable task, long timeout, TimeUnit unit) + throws TimeoutException { + Future future = executor.submit(task); + + try { + return future.get(timeout, unit); + } catch (java.util.concurrent.TimeoutException e) { + future.cancel(true); + throw new TimeoutException("Operation timed out", e); + } +} +``` + +## Class diagram + +![Timeout Pattern UML](./etc/timeout.urm.png) + +## Applicability + +Use the Timeout pattern when: + +- Operations might block indefinitely due to network issues, slow services, or resource contention +- You need to maintain system responsiveness even when dependencies are slow +- Cascading failures need to be prevented in distributed systems +- SLA requirements mandate maximum response times +- You want to implement circuit breaker or retry patterns + +## Known Uses + +- HTTP client libraries (setting connection and read timeouts) +- Database connection pools (query timeouts) +- Microservices communication (service-to-service call timeouts) +- Message queue consumers (message processing timeouts) +- RPC frameworks (remote procedure call timeouts) + +## Consequences + +Benefits: +- Prevents indefinite blocking and resource exhaustion +- Improves system responsiveness and user experience +- Enables better error handling and recovery strategies +- Helps maintain SLA commitments +- Prevents cascading failures in distributed systems + +Trade-offs: +- Requires careful tuning of timeout values +- May need retry logic for transient failures +- Can increase system complexity +- Might cancel operations that would have eventually succeeded + +## Related Patterns + +- Circuit Breaker: Often used together; circuit breaker opens after multiple timeout failures +- Retry: Used to handle timeout exceptions by retrying the operation +- Bulkhead: Isolates resources to prevent timeout cascades +- Async Method Invocation: Provides non-blocking execution with timeout support + +## Credits + +- [Microsoft Azure - Timeout Pattern](https://docs.microsoft.com/en-us/azure/architecture/patterns/timeout) +- [Release It!: Design and Deploy Production-Ready Software](https://www.amazon.com/Release-Design-Deploy-Production-Ready-Software/dp/1680502395) +- [Building Microservices: Designing Fine-Grained Systems](https://www.amazon.com/Building-Microservices-Designing-Fine-Grained-Systems/dp/1491950358) \ No newline at end of file diff --git a/timeout/etc/timeout.urm.png.png b/timeout/etc/timeout.urm.png.png new file mode 100644 index 0000000000000000000000000000000000000000..1aaec1846050424e09ead08a6f05b5f07060fe23 GIT binary patch literal 32627 zcmdqJXH-+`-!_Qdg968bbg@trL{OS^6s1a$E-fO`r3MHPLR1t)nt*`x-b}jI=3Q$(%)D#Xn&(5<$=>_k_ujw$yY6cfX=I?q#>&ge z!otF)qy5;Jh2=Ps`KdX3nz`q$(tHwga|~##^@ycvkbjx^`yU& z|K+Xy9LU1L-g)#n*5g(3iiHJwR_F0U(?B~C9TH-?oylOR5jvBXn+x5eJZ?{qzCU;A z_&u&X+d@xH+sJ~y3+GOYh^YNIJh(-J{|VD}I~9MfaMmqi$6~4Gl2M3aU$RNB=B6{MXFoO~~8Uwhj_4@l>mg;Yt31P!|5rM

*e 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, timeout: long, unit: TimeUnit): T + + shutdown(): void + } + + class App { + + {static} main(args: String[]): void + } + + TimeoutHandler ..> TimeoutException : throws + App ..> TimeoutHandler : uses + App ..> TimeoutException : catches +} + +note right of TimeoutHandler + Executes tasks with timeout constraints. + Uses ExecutorService to run tasks + asynchronously and enforce time limits. +end note + +note right of TimeoutException + Custom exception thrown when + an operation exceeds its + timeout duration. +end note + +@enduml \ No newline at end of file diff --git a/timeout/pom.xml b/timeout/pom.xml new file mode 100644 index 000000000000..6f8f36f133f4 --- /dev/null +++ b/timeout/pom.xml @@ -0,0 +1,32 @@ + + + 4.0.0 + + + com.iluwatar + java-design-patterns + 1.26.0-SNAPSHOT + + + timeout + jar + + + + org.projectlombok + lombok + + + ch.qos.logback + logback-classic + + + org.junit.jupiter + junit-jupiter-engine + test + + + + \ No newline at end of file diff --git a/timeout/src/main/java/com/iluwatar/timeout/App.java b/timeout/src/main/java/com/iluwatar/timeout/App.java new file mode 100644 index 000000000000..071a89cc4e66 --- /dev/null +++ b/timeout/src/main/java/com/iluwatar/timeout/App.java @@ -0,0 +1,517 @@ + +Hi Claude! Could you develop content briefs? If you need more information from me, ask me 1-2 key questions right away. If you think I should upload any documents that would help you do a better job, let me know. You can use the tools you have access to β€” like Google Drive, web search, etc. β€” if they’ll help you better accomplish this task. Do not use analysis tool. Please keep your responses friendly, brief and conversational. + +Please execute the task as soon as you can - an artifact would be great if it makes sense. If using an artifact, consider what kind of artifact (interactive, visual, checklist, etc.) might be most helpful for this specific task. Thanks for your help! + +Hey there! Yes, I'd be happy to help you develop content briefs! + +Before I dive in, let me ask you a couple of key questions: + +What type of content are these briefs for? (e.g., blog posts, social media, videos, email campaigns, landing pages) +Do you have a specific topic/campaign in mind, or would you like me to create a template you can reuse for different projects? +Also, if you have any existing brand guidelines, competitor content, or target audience documents, those would be super helpful to upload! Otherwise, I can work with whatever details you share. + +I am a beginner and want to contribute on github for hactoberfest... I attatched my editor screen... and want from you to solve issue and tell me stap by step to make changes in all the things.... + +Hey! I can see you're working on a GitHub project for Hacktoberfest - that's awesome! + +However, I'm not able to see the image you mentioned attaching. Could you try uploading it again? + +In the meantime, to help you better, let me know: + +What's the issue you're trying to solve? (Is there a specific GitHub issue number or description?) +What repository are you contributing to? (The repo name or URL would help) +Once I can see your editor screen and understand the issue, I'll walk you through the solution step-by-step - from making the code changes to creating your pull request. Don't worry, we'll make this beginner-friendly! πŸš€ + +1759382802691_image.png +here is my screen + +Perfect! I can see your VS Code is open with a Hacktoberfest folder. Now I need a bit more info to help you solve the issue: + +Can you tell me: + +What's the specific issue or task you need to complete? (Is there a GitHub issue description, or a feature you want to add?) +What programming language/project is this? (Python, JavaScript, web development, etc.) +Also, could you: + +Click on the "HACKTOBERFEST" folder in the left sidebar to expand it and show me the files inside? +Or share the GitHub repository link so I can see what the project is about? +Once I understand what you're trying to build or fix, I'll create a step-by-step guide for you covering: + +Writing the code +Testing it +Committing changes +Creating a pull request +Let's get your first Hacktoberfest contribution done! πŸŽ‰ + +I am just telling you the editor and path... I will fork the project and after that ask the help for you + +Got it! That's a smart approach. + +So here's what you'll do: + +Fork the repository on GitHub (click the "Fork" button on the repo page) +Clone your forked repo to your local machine +Find an issue you want to work on (look for labels like "good first issue" or "hacktoberfest") +Come back here with: +The issue description or what you need to fix +Any relevant code files +Screenshots if needed +Then I'll give you a complete step-by-step solution including the exact code changes and Git commands you'll need! + +Take your time, and just ping me when you're ready. Good luck with the fork! πŸš€ + +i found an issue... how to check if the issue is open and anybody make PR for it + +Great question! Here's how to check: + +1. Check if the issue is still open: + +Look at the issue page - if it says "Open" with a green icon, it's available +If it says "Closed" with a purple icon, skip it +2. Check if someone already made a PR for it: + +Scroll down on the issue page to see the comments/timeline +Look for any linked pull requests (they'll show up as "#123" links) +Click on the PR number to see if it's merged, closed, or still open +3. Check the PR tab: + +Go to the repository's "Pull Requests" tab +Search for PRs that mention the issue number +If there's an open PR already working on it, find a different issue +Pro tip: Comment on the issue saying "I'd like to work on this!" before you start. This lets maintainers know you're on it and prevents duplicate work. + +Want to share the issue link? I can quickly check it for you and confirm if it's available! πŸ‘€ + +https://github.com/iluwatar/java-design-patterns/issues/2977 +here is the issue link can you find for PR + +favicon + +Fetched Fix busy-waiting loops Β· Issue #2977 Β· iluwatar/java-design-patterns +github.com + +Let me search for more details about this issue and check for any related PRs: + + +java-design-patterns issue 2977 busy-waiting loops +10 results + + + + + + + + + + + + + + + + + + + + + +Perfect! I found something important: + +⚠️ There's already a PR for this issue! + +PR #3123 by Mostafa-Hisham0 is addressing issue #2977. The PR is titled "Refactor Busy-Waiting Loops to Improve Efficiency" and it's working on fixing the exact busy-waiting problem you're looking at. + +What you should do: + +Find a different issue - This one is being worked on +Look for issues labeled: +"good first issue" +"help wanted" +"hacktoberfest" +Make sure to check comments and linked PRs before starting work +Want me to help you find another good beginner-friendly issue in this repo? I can search for available ones that nobody has claimed yet! Just let me know. 😊 + +https://github.com/iluwatar/java-design-patterns/issues/2845 +check for this issue + +favicon + +Fetched Timeout pattern Β· Issue #2845 Β· iluwatar/java-design-patterns +github.com + + +java-design-patterns issue 2845 timeout pattern pull request +10 results + + + + + + + + + + + + + + + + + + + + + + +"iluwatar/java-design-patterns" "2845" PR +1 result + + + +Good news! This issue appears to be available! πŸŽ‰ + +Issue #2845 is asking to implement a "Timeout Pattern" - a microservices design pattern that helps prevent long waits and cascading failures. + +From what I can see: + +βœ… Issue is still OPEN +βœ… No linked pull requests found +βœ… It's a feature request to add a new design pattern +Before you start working on it: + +Comment on the issue saying "I'd like to work on this for Hacktoberfest!" to claim it +Wait for maintainer approval (important for this repo!) +Fork the repo to your account +This is a bigger task - you'll need to create: + +Java implementation of the Timeout pattern +README documentation +Example code +Tests +Are you comfortable with Java? This might be challenging for a beginner. Want me to help you find a simpler "good first issue" instead, or are you ready to tackle this one? Let me know! 😊 + +if you are with me we can solve it.... can you do all the work... I meant that will you tell me all the changes to make + +Absolutely! I'm with you 100%! πŸš€ + +Yes, I'll guide you through every single step - from writing the code to submitting the PR. I'll tell you: + +Exactly what files to create +The complete code for each file +Where to put them +Git commands to run +How to make the PR +Here's our game plan: + +First, comment on the issue to claim it (prevents others from working on it) +Fork the repo to your GitHub account +Clone it to your local machine +I'll give you the complete code structure for the Timeout pattern +You'll copy-paste the code I provide +We'll test it together +Commit and push (I'll give you the commands) +Create the Pull Request +Before we dive in - quick question: Do you have basic Java knowledge? You don't need to be an expert, but understanding basic Java syntax will help you learn from this. Even if you're a beginner, we can do this together! + +Ready to start? Comment on the issue first, then let me know once you've forked and cloned the repo! πŸ’ͺ + +yes I knew that's why I selected this one + +Perfect! Let's do this! πŸ’ͺ + +Step 1: Claim the Issue Go to the issue page and comment: + +Hi! I'd like to work on implementing the Timeout pattern for Hacktoberfest. I'll submit a PR soon. Thanks! +Step 2: Fork & Clone + +Click "Fork" on the repo page (top right) +Once forked, clone YOUR fork: +bash +git clone https://github.com/YOUR-USERNAME/java-design-patterns.git +cd java-design-patterns +Step 3: Create a new branch + +bash +git checkout -b timeout-pattern +Once you've done these steps, let me know and I'll give you: + +The complete folder structure +All the Java code files +README documentation +Everything you need to copy-paste +Question: Have you already forked the repo? If yes, just let me know and we'll jump straight into the code! πŸ”₯ + + +1759383697764_image.png +https://github.com/dyrpsf/java-design-patterns +I forked the project and clone it into my system +the screen looks like + +Awesome! You've cloned it successfully! πŸŽ‰ + +I can see the project structure. Now let's create the Timeout pattern! + +Step 1: Create the branch In your terminal, run: + +bash +git checkout -b timeout-pattern +Step 2: Create the folder structure We need to create a new folder called timeout in the root directory (same level as adapter, builder, etc.) + +In your terminal: + +bash +mkdir timeout +cd timeout +mkdir src +cd src +mkdir main +cd main +mkdir java +cd java +mkdir com +cd com +mkdir iluwatar +cd iluwatar +mkdir timeout +cd timeout +mkdir etc +Or the quick way: + +bash +mkdir -p timeout/src/main/java/com/iluwatar/timeout/etc +mkdir -p timeout/src/test/java/com/iluwatar/timeout +Ready for the code? Once you've created the folders, I'll give you all the Java files to create. Let me know when you're ready for the next step! πŸ’ͺ + + +1759383767337_image.png +WHAT IS THIS i am getting the error + +No worries! This is a Git warning, not an error. It's happening because you're on Windows and there are some files with case-sensitive naming issues. + +Let's fix this and continue: + +Step 1: First, let's initialize Git properly in your folder Run this command: + +bash +git init +Step 2: Then create the branch + +bash +git checkout -b timeout-pattern +If that still gives issues, try: + +bash +git config core.ignorecase false +git checkout -b timeout-pattern +Step 3: If it still doesn't work, let's just create the folders manually + +Instead of using terminal commands, let's do it visually: + +Right-click on java-design-patterns folder in VS Code Explorer (left sidebar) +Click "New Folder" +Name it timeout +Inside timeout, create these folders step by step: +src β†’ main β†’ java β†’ com β†’ iluwatar β†’ timeout +etc (inside the last timeout folder) +Can you try creating the branch with the git commands above, or shall we just create the folders manually in VS Code? Let me know what works! 😊 + + +1759383821893_image.png +it works now please tell me steps + +Perfect! Great job! πŸŽ‰ Now let's create the Timeout pattern files. + +Step 1: Create the folder structure + +Run these commands one by one: + +bash +mkdir timeout +cd timeout +mkdir -p src/main/java/com/iluwatar/timeout +mkdir -p src/test/java/com/iluwatar/timeout +mkdir etc +Step 2: Navigate back to root + +bash +cd .. +Now let's create the files. I'll give you the complete code for each file. + +Are you ready? I'll create an artifact with all the files and their content, then tell you where to place each one. Sound good? πŸ’ͺ + + +yes I have completed all the stuffs you send + +Awesome! Now let's create all the Java files! πŸš€ + +I'll give you the complete code for each file. Create these files in your timeout folder: + +TimeoutException.java +Code +Perfect! Now let me create the remaining files. Here's file 3: + +App.java +Code +Now let me create the test file and README: + +TimeoutHandlerTest.java +Code +Now the README and pom.xml: + +README.md +Document +Perfect! Now let me give you the file placement instructions: + +πŸ“ FILE PLACEMENT GUIDE: + +Create these files in your timeout folder: + +TimeoutException.java +Path: timeout/src/main/java/com/iluwatar/timeout/TimeoutException.java +Copy the code from the first artifact +TimeoutHandler.java +Path: timeout/src/main/java/com/iluwatar/timeout/TimeoutHandler.java +Copy the code from the second artifact +App.java +Path: timeout/src/main/java/com/iluwatar/timeout/App.java +Copy the code from the third artifact +TimeoutHandlerTest.java +Path: timeout/src/test/java/com/iluwatar/timeout/TimeoutHandlerTest.java +Copy the code from the fourth artifact +README.md +Path: timeout/README.md +Copy the markdown from the fifth artifact +pom.xml +Path: timeout/pom.xml +Copy the XML from the sixth artifact +Next step: Once you've created all these files, let me know and I'll help you with the UML diagram and then we'll commit everything! πŸš€ + +I have to create file the files which you sent to me in timeout folder or etc or src folder + +Great question! Let me clarify the exact folder structure: + +Create these folders first (if not done already): + +timeout/ +β”œβ”€β”€ src/ +β”‚ β”œβ”€β”€ main/ +β”‚ β”‚ └── java/ +β”‚ β”‚ └── com/ +β”‚ β”‚ └── iluwatar/ +β”‚ β”‚ └── timeout/ +β”‚ └── test/ +β”‚ └── java/ +β”‚ └── com/ +β”‚ └── iluwatar/ +β”‚ └── timeout/ +β”œβ”€β”€ etc/ +β”œβ”€β”€ README.md +└── pom.xml +Now place the files: + +TimeoutException.java β†’ timeout/src/main/java/com/iluwatar/timeout/ +TimeoutHandler.java β†’ timeout/src/main/java/com/iluwatar/timeout/ +App.java β†’ timeout/src/main/java/com/iluwatar/timeout/ +TimeoutHandlerTest.java β†’ timeout/src/test/java/com/iluwatar/timeout/ +README.md β†’ timeout/ (root of timeout folder) +pom.xml β†’ timeout/ (root of timeout folder) +The etc folder will be for the UML diagram image (we'll add that next). + +So to summarize: + +Java source files β†’ src/main/java/com/iluwatar/timeout/ +Test files β†’ src/test/java/com/iluwatar/timeout/ +README & pom.xml β†’ directly in timeout/ folder +Got it? 😊 + + + + + + +package com.iluwatar.timeout; + +import java.util.concurrent.TimeUnit; +import lombok.extern.slf4j.Slf4j; + +/** + * The Timeout pattern is used to prevent indefinite blocking when waiting for operations. + * It sets a maximum time limit for an operation, after which the operation is cancelled + * and control is returned to the caller with an error. + * + *

This pattern is particularly useful in distributed systems and microservices where: + *

    + *
  • Network calls might hang indefinitely
  • + *
  • External services might be slow or unresponsive
  • + *
  • Database queries might take too long
  • + *
  • Resource contention needs to be managed
  • + *
+ * + *

In this example, we demonstrate the Timeout pattern by simulating: + *

    + *
  • A fast service call that completes within timeout
  • + *
  • A slow service call that exceeds the timeout
  • + *
+ */ +@Slf4j +public class App { + + /** + * Program entry point. + * + * @param args command line arguments + */ + public static void main(String[] args) { + LOGGER.info("Starting Timeout Pattern demonstration"); + + TimeoutHandler handler = new TimeoutHandler(); + + // Example 1: Fast service call (completes within timeout) + try { + LOGGER.info("\n--- Example 1: Fast Service Call ---"); + String result = handler.execute(() -> { + LOGGER.info("Fast service: Processing request..."); + Thread.sleep(1000); // Simulate 1 second processing + return "Fast service completed"; + }, 3, TimeUnit.SECONDS); + + LOGGER.info("Result: {}", result); + } catch (TimeoutException e) { + LOGGER.error("Fast service failed: {}", e.getMessage()); + } + + // Example 2: Slow service call (exceeds timeout) + try { + LOGGER.info("\n--- Example 2: Slow Service Call ---"); + String result = handler.execute(() -> { + LOGGER.info("Slow service: Processing request..."); + Thread.sleep(5000); // Simulate 5 second processing + return "Slow service completed"; + }, 2, TimeUnit.SECONDS); + + LOGGER.info("Result: {}", result); + } catch (TimeoutException e) { + LOGGER.error("Slow service timed out: {}", e.getMessage()); + } + + // Example 3: Database query with timeout + try { + LOGGER.info("\n--- Example 3: Database Query with Timeout ---"); + String result = handler.execute(() -> { + LOGGER.info("Executing database query..."); + Thread.sleep(1500); // Simulate database query + return "Query result: 42 records"; + }, 2, TimeUnit.SECONDS); + + LOGGER.info("Result: {}", result); + } catch (TimeoutException e) { + LOGGER.error("Database query failed: {}", e.getMessage()); + } + + handler.shutdown(); + LOGGER.info("\nTimeout Pattern demonstration completed"); + } +} diff --git a/timeout/src/main/java/com/iluwatar/timeout/TimeoutException.java b/timeout/src/main/java/com/iluwatar/timeout/TimeoutException.java new file mode 100644 index 000000000000..d7394b9f9527 --- /dev/null +++ b/timeout/src/main/java/com/iluwatar/timeout/TimeoutException.java @@ -0,0 +1,15 @@ +package com.iluwatar.timeout; + +/** + * Exception thrown when an operation times out. + */ +public class TimeoutException extends Exception { + + public TimeoutException(String message) { + super(message); + } + + public TimeoutException(String message, Throwable cause) { + super(message, cause); + } +} \ No newline at end of file diff --git a/timeout/src/main/java/com/iluwatar/timeout/TimeoutHandler.java b/timeout/src/main/java/com/iluwatar/timeout/TimeoutHandler.java new file mode 100644 index 000000000000..94eae1ffa256 --- /dev/null +++ b/timeout/src/main/java/com/iluwatar/timeout/TimeoutHandler.java @@ -0,0 +1,67 @@ +package com.iluwatar.timeout; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.concurrent.TimeUnit; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +/** + * Tests for TimeoutHandler. + */ +class TimeoutHandlerTest { + + private TimeoutHandler handler; + + @BeforeEach + void setUp() { + handler = new TimeoutHandler(); + } + + @AfterEach + void tearDown() { + handler.shutdown(); + } + + @Test + void testSuccessfulExecution() throws TimeoutException { + String result = handler.execute(() -> { + Thread.sleep(100); + return "Success"; + }, 1, TimeUnit.SECONDS); + + assertEquals("Success", result); + } + + @Test + void testTimeoutException() { + TimeoutException exception = assertThrows(TimeoutException.class, () -> { + handler.execute(() -> { + Thread.sleep(3000); + return "Should timeout"; + }, 1, TimeUnit.SECONDS); + }); + + assertTrue(exception.getMessage().contains("timed out")); + } + + @Test + void testImmediateReturn() throws TimeoutException { + String result = handler.execute(() -> "Immediate", 1, TimeUnit.SECONDS); + assertEquals("Immediate", result); + } + + @Test + void testTaskThrowsException() { + TimeoutException exception = assertThrows(TimeoutException.class, () -> { + handler.execute(() -> { + throw new RuntimeException("Task failed"); + }, 1, TimeUnit.SECONDS); + }); + + assertTrue(exception.getMessage().contains("Operation failed")); + } +} \ No newline at end of file diff --git a/timeout/src/test/java/com/iluwatar/timeout/TimeoutHandlerTest.java b/timeout/src/test/java/com/iluwatar/timeout/TimeoutHandlerTest.java new file mode 100644 index 000000000000..94eae1ffa256 --- /dev/null +++ b/timeout/src/test/java/com/iluwatar/timeout/TimeoutHandlerTest.java @@ -0,0 +1,67 @@ +package com.iluwatar.timeout; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.concurrent.TimeUnit; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +/** + * Tests for TimeoutHandler. + */ +class TimeoutHandlerTest { + + private TimeoutHandler handler; + + @BeforeEach + void setUp() { + handler = new TimeoutHandler(); + } + + @AfterEach + void tearDown() { + handler.shutdown(); + } + + @Test + void testSuccessfulExecution() throws TimeoutException { + String result = handler.execute(() -> { + Thread.sleep(100); + return "Success"; + }, 1, TimeUnit.SECONDS); + + assertEquals("Success", result); + } + + @Test + void testTimeoutException() { + TimeoutException exception = assertThrows(TimeoutException.class, () -> { + handler.execute(() -> { + Thread.sleep(3000); + return "Should timeout"; + }, 1, TimeUnit.SECONDS); + }); + + assertTrue(exception.getMessage().contains("timed out")); + } + + @Test + void testImmediateReturn() throws TimeoutException { + String result = handler.execute(() -> "Immediate", 1, TimeUnit.SECONDS); + assertEquals("Immediate", result); + } + + @Test + void testTaskThrowsException() { + TimeoutException exception = assertThrows(TimeoutException.class, () -> { + handler.execute(() -> { + throw new RuntimeException("Task failed"); + }, 1, TimeUnit.SECONDS); + }); + + assertTrue(exception.getMessage().contains("Operation failed")); + } +} \ No newline at end of file From ea2f22db4e8ebbda11fbcb1935b05913d3ac52eb Mon Sep 17 00:00:00 2001 From: dyrpsf Date: Thu, 2 Oct 2025 12:20:57 +0530 Subject: [PATCH 2/2] Fix image filename - remove duplicate .png extension --- .../etc/{timeout.urm.png.png => timeout.urm.png} | Bin 1 file changed, 0 insertions(+), 0 deletions(-) rename timeout/etc/{timeout.urm.png.png => timeout.urm.png} (100%) diff --git a/timeout/etc/timeout.urm.png.png b/timeout/etc/timeout.urm.png similarity index 100% rename from timeout/etc/timeout.urm.png.png rename to timeout/etc/timeout.urm.png