{"id":231387,"date":"2024-08-27T09:09:24","date_gmt":"2024-08-27T16:09:24","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/java\/?p=231387"},"modified":"2024-11-17T22:50:24","modified_gmt":"2024-11-18T06:50:24","slug":"reliable-web-app-reliability-patterns","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/java\/reliable-web-app-reliability-patterns\/","title":{"rendered":"Reliable Web App \u2013 Reliability Patterns"},"content":{"rendered":"<div class=\"flex max-w-full flex-col flex-grow\">\n<div class=\"min-h-[20px] text-message flex w-full flex-col items-end gap-2 break-words [.text-message+&amp;]:mt-5 overflow-x-auto whitespace-normal\" dir=\"auto\" data-message-author-role=\"assistant\" data-message-id=\"e060e2c6-45d5-4d08-8b13-239705990bd2\">\n<div class=\"flex w-full flex-col gap-1 empty:hidden first:pt-[3px]\">\n<div class=\"markdown prose w-full break-words dark:prose-invert dark\"><span style=\"font-size: 1rem; text-align: var(--bs-body-text-align);\">As applications migrate to the cloud, they must be designed to handle inevitable failures gracefully. <\/span><span style=\"font-size: 1rem; text-align: var(--bs-body-text-align);\" data-teams=\"true\"><span class=\"ui-provider a b c d e f g h i j k l m n o p q r s t u v w x y z ab ac ae af ag ah ai aj ak\" dir=\"ltr\">Network issues, service outages, and other transient faults are common in distributed systems<\/span><\/span><span style=\"font-size: 1rem; text-align: var(--bs-body-text-align);\">. Without proper handling mechanisms, these failures can lead to system instability and poor user experiences. This is why Retry and Circuit Breaker patterns are essential. The Retry pattern allows applications to recover from temporary failures by reattempting failed operations, while the Circuit Breaker pattern helps prevent cascading failures by stopping attempts to perform an action that is likely to fail, thereby maintaining the overall health of the system.<\/span><\/div>\n<\/div>\n<\/div>\n<\/div>\n<p>You can think of the Reliable Web Application (RWA) pattern as a pattern of patterns. Each pattern provides prescriptive guidance on how to build a specific aspect of a reliable web application. The patterns are derived from both the Azure Well-Architected Framework and the 12-factor app methodology.<\/p>\n<p>In this blog, we&#8217;ll demo both the Retry and the Circuit Breaker patterns. The retry pattern involves making repeated attempts to execute a task until successful, while the circuit-breaker pattern prevents a system from executing a task that&#8217;s likely to fail, to avoid further system degradation.<\/p>\n<div>\n<div><span style=\"font-size: 18pt; color: inherit; font-family: inherit; text-align: var(--bs-body-text-align);\">Installation<\/span><\/div>\n<\/div>\n<p class=\"code-line\" dir=\"auto\" data-line=\"2\">To run the simple demo, you&#8217;ll need:<\/p>\n<ul class=\"code-line\" dir=\"auto\" data-line=\"8\">\n<li class=\"code-line\" dir=\"auto\" data-line=\"8\"><strong>Java Development Kit (JDK) 17<\/strong>: Essential for developing Java applications. Make sure to install JDK 17 as specified in your\u00a0<code>pom.xml<\/code>\u00a0file.\u00a0<a title=\"https:\/\/jdk.java.net\/17\/\" href=\"https:\/\/learn.microsoft.com\/en-us\/java\/openjdk\/download#openjdk-17\" data-href=\"https:\/\/jdk.java.net\/17\/\">Download JDK 17<\/a><\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"9\"><strong>Apache Maven<\/strong>: A build automation tool used primarily for Java projects. It helps manage project dependencies and streamline the build process.\u00a0<a title=\"https:\/\/maven.apache.org\/download.cgi\" href=\"https:\/\/maven.apache.org\/download.cgi\" data-href=\"https:\/\/maven.apache.org\/download.cgi\">Download Maven<\/a><\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"10\"><strong>Visual Studio Code<\/strong>: A lightweight but powerful source code editor that runs on your desktop. It&#8217;s available for Windows, macOS, and Linux.\u00a0<a title=\"https:\/\/code.visualstudio.com\/Download\" href=\"https:\/\/code.visualstudio.com\/Download\" data-href=\"https:\/\/code.visualstudio.com\/Download\">Download Visual Studio Code<\/a><\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"11\"><strong>Java Extension Pack for Visual Studio Code<\/strong>: This extension pack includes essential Java tools such as Maven support and Java 17 compatibility.\u00a0<a title=\"https:\/\/marketplace.visualstudio.com\/items?itemName=vscjava.vscode-java-pack\" href=\"https:\/\/marketplace.visualstudio.com\/items?itemName=vscjava.vscode-java-pack\" data-href=\"https:\/\/marketplace.visualstudio.com\/items?itemName=vscjava.vscode-java-pack\">Download Java Extension Pack<\/a><\/li>\n<\/ul>\n<p>Clone the sample repo<\/p>\n<pre class=\"prettyprint language-default\"><code class=\"language-default\">git clone https:\/\/github.com\/Azure\/reliable-web-app-pattern-java.git<\/code><\/pre>\n<p>Navigate to the project directory:<\/p>\n<pre>cd reliable-web-app-pattern-java\/workshop\/Part0-Basic-App\/src\r\n<\/pre>\n<p>Install dependencies:<\/p>\n<pre>mvn clean install\r\n<\/pre>\n<p>St<span style=\"font-size: 1rem; text-align: var(--bs-body-text-align);\">art the application using Maven:<\/span><\/p>\n<pre>mvn spring-boot:run\r\n<\/pre>\n<p class=\"code-line\" dir=\"auto\" data-line=\"52\">You can then access the API at\u00a0<code>http:\/\/localhost:8080\/product\/1<\/code>.<\/p>\n<h3 id=\"example-api-call\" class=\"code-line\" dir=\"auto\" data-line=\"54\"><span style=\"font-size: 18pt;\">Example API Call<\/span><\/h3>\n<p class=\"code-line\" dir=\"auto\" data-line=\"56\">To retrieve a product by its ID, you can use the following curl command:<\/p>\n<pre class=\"prettyprint language-default\"><code class=\"language-default\">curl http:\/\/localhost:8080\/product\/1<\/code><\/pre>\n<h3 dir=\"auto\" data-line=\"64\"><span style=\"font-size: 18pt;\">Running the Tests<\/span><\/h3>\n<p class=\"code-line\" dir=\"auto\" data-line=\"64\">To run the automated tests for this system, use the following command:<\/p>\n<pre>mvn test<\/pre>\n<p class=\"code-line\" dir=\"auto\" data-line=\"70\">These tests verify the functionality of all components, ensuring that the application behaves as expected.<\/p>\n<h2 id=\"failure-mode\" class=\"code-line\" dir=\"auto\" data-line=\"72\"><span style=\"font-size: 18pt;\">Failure Mode<\/span><\/h2>\n<p class=\"code-line\" dir=\"auto\" data-line=\"74\">One of the most essential principles of the Reliable Web App pattern is the Retry Pattern. It helps your application deal with situations where a service might be temporarily down, a \u2018transient fault\u2019. The Retry pattern resends failed requests to the service until it\u2019s working again.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"76\">But the Retry Pattern alone is not enough. Sometimes, a service might be unavailable for a long time, or it might even be gone forever. It would be useless to keep trying to call such a service. That\u2019s why we need the Circuit Breaker Pattern.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"78\">The application includes a feature to simulate failures, useful for testing its resilience capabilities such as the circuit breaker and retry mechanisms. This simulation can be controlled directly from a web browser, making it easy to demonstrate or test the effects of these patterns.<\/p>\n<h3 id=\"enabling-failures\" class=\"code-line\" dir=\"auto\" data-line=\"80\"><span style=\"font-size: 18pt;\">Enabling Failures<\/span><\/h3>\n<p class=\"code-line\" dir=\"auto\" data-line=\"82\">To simulate failures in the system, which will trigger the circuit breaker or retry logic, you can activate failure mode using the following URL:<\/p>\n<pre>http:\/\/localhost:8080\/configure\/failure?fail=true\r\n<\/pre>\n<p class=\"code-line\" dir=\"auto\" data-line=\"87\">You can then trigger the failure at\u00a0http:\/\/localhost:8080\/product\/1.<\/p>\n<p dir=\"auto\" data-line=\"87\"><a href=\"https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2024\/08\/failure-web.png\"><img decoding=\"async\" class=\"alignnone wp-image-231390\" src=\"https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2024\/08\/failure-web.png\" alt=\"Image failure web\" width=\"814\" height=\"284\" srcset=\"https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2024\/08\/failure-web.png 1126w, https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2024\/08\/failure-web-300x105.png 300w, https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2024\/08\/failure-web-1024x357.png 1024w, https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2024\/08\/failure-web-768x268.png 768w\" sizes=\"(max-width: 814px) 100vw, 814px\" \/><\/a><\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"89\">View the logs in your browser and terminal:<\/p>\n<h3 dir=\"auto\" data-line=\"94\"><a href=\"https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2024\/08\/failure.png\"><img decoding=\"async\" class=\"alignnone wp-image-231391\" src=\"https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2024\/08\/failure.png\" alt=\"Image failure\" width=\"819\" height=\"191\" srcset=\"https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2024\/08\/failure.png 2281w, https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2024\/08\/failure-300x70.png 300w, https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2024\/08\/failure-1024x239.png 1024w, https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2024\/08\/failure-768x179.png 768w, https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2024\/08\/failure-1536x358.png 1536w, https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2024\/08\/failure-2048x478.png 2048w\" sizes=\"(max-width: 819px) 100vw, 819px\" \/><\/a><\/h3>\n<h3 id=\"disabling-failures\" class=\"code-line\" dir=\"auto\" data-line=\"94\"><span style=\"font-size: 18pt;\">Disabling Failures<\/span><\/h3>\n<p class=\"code-line\" dir=\"auto\" data-line=\"96\">To return the system to normal operation, disable the failure mode using this URL:<\/p>\n<pre>http:\/\/localhost:8080\/configure\/failure?fail=false\r\n<\/pre>\n<p class=\"code-line\" dir=\"auto\" data-line=\"101\">Test the application again by accessing<code class=\"language-default\">http:\/\/localhost:8080\/product\/1<\/code><\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"104\">Remember to close your terminal by pressing\u00a0<code>Ctrl+C<\/code>\u00a0to stop the application.<\/p>\n<h2 id=\"circuit-breaker-in-testing\" class=\"code-line\" dir=\"auto\" data-line=\"107\"><span style=\"font-size: 18pt;\">Circuit Breaker in Testing<\/span><\/h2>\n<p class=\"code-line\" dir=\"auto\" data-line=\"109\">The circuit breaker pattern is crucial for managing failures in distributed systems. It prevents a network or service failure from causing your application to become unstable. This pattern temporarily halts operations when a particular service or operation fails repeatedly, which is vital for maintaining overall system health.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"111\">The\u00a0<code>ProductServiceTest<\/code> class in the<code class=\"language-default\">src\/test\/java\/com\/example\/demo\/service\/ProductServiceTest.java <\/code>tests this behavior by simulating failures to trigger the circuit breaker. Here&#8217;s an explanation of the test and the method it tests:<\/p>\n<h3 id=\"code-snippets-and-explanation\" class=\"code-line\" dir=\"auto\" data-line=\"113\"><span style=\"font-size: 18pt;\">Code Snippets and Explanation<\/span><\/h3>\n<p class=\"code-line\" dir=\"auto\" data-line=\"115\"><strong>getProductById Method in ProductService<\/strong><\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"117\">This method includes a circuit breaker and retry mechanism, which are critical for handling failures in production environments. Here\u2019s how it works:<\/p>\n<pre>    @CircuitBreaker(name = \"default\", fallbackMethod = \"fallback\")\r\n    @Retry(name = \"default\")\r\n    public Product getProductById(Long id) {\r\n        if (failForCircuitBreakerTest || Math.random() &gt; 0.7) {\r\n            throw new RuntimeException(\"Service failure - Circuit breaker activated\");\r\n        }\r\n        return new Product(id, \"Product Name\", \"Product Description\");\r\n    }\r\n<\/pre>\n<p class=\"code-line\" dir=\"auto\" data-line=\"129\">The line\u00a0<code>if (failForCircuitBreakerTest || Math.random() &gt; 0.7)<\/code>\u00a0in the\u00a0<code>getProductById<\/code>\u00a0method is crucial for testing and demonstrating the resilience of the application. It simulates failures by combining a manual flag (<code>failForCircuitBreakerTest<\/code>) and a random factor (<code>Math.random() &gt; 0.7<\/code>). This setup allows developers to trigger failure scenarios and introduces unpredictability, mimicking real-world conditions. By validating the system&#8217;s fault tolerance mechanisms, it ensures reliable service even under adverse conditions.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"131\"><strong>ProductServiceTest Class<\/strong><\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"133\">The test method simulates a scenario where the\u00a0<code>getProductById<\/code>\u00a0method is called and a failure is expected to trigger the circuit breaker:<\/p>\n<pre><code class=\"code-line language-java\" dir=\"auto\" data-line=\"135\">    <span class=\"hljs-meta\">@Test<\/span>\r\n    <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title function_\">whenGetProductByIdCalledMultipleTimes_thenCircuitBreakerShouldBeTriggered<\/span><span class=\"hljs-params\">()<\/span> {\r\n        <span class=\"hljs-type\">boolean<\/span> <span class=\"hljs-variable\">exceptionThrown<\/span> <span class=\"hljs-operator\">=<\/span> <span class=\"hljs-literal\">false<\/span>;\r\n        <span class=\"hljs-keyword\">for<\/span> (<span class=\"hljs-type\">int<\/span> <span class=\"hljs-variable\">i<\/span> <span class=\"hljs-operator\">=<\/span> <span class=\"hljs-number\">0<\/span>; i &lt; <span class=\"hljs-number\">20<\/span>; i++) {\r\n            <span class=\"hljs-keyword\">try<\/span> {\r\n                productService.getProductById((<span class=\"hljs-type\">long<\/span>) i);\r\n            } <span class=\"hljs-keyword\">catch<\/span> (RuntimeException e) {\r\n                exceptionThrown = <span class=\"hljs-literal\">true<\/span>;\r\n            }\r\n        }\r\n        assertTrue(exceptionThrown);\r\n    }\r\n<\/code><\/pre>\n<p class=\"code-line\" dir=\"auto\" data-line=\"150\">This test ensures that the circuit breaker is functioning as expected by verifying that an exception is thrown when the method is repeatedly called under failure conditions.<\/p>\n<h2 id=\"conclusion\" class=\"code-line\" dir=\"auto\" data-line=\"154\"><span style=\"font-size: 18pt;\">Conclusion<\/span><\/h2>\n<p>This project provides a simple demonstration of two Reliable Web App patterns in action. By exploring the code and running the application, you can gain a better understanding of how these patterns can enhance the reliability and performance of web applications.<\/p>\n<h3><span style=\"font-size: 18pt;\">What\u2019s Next?<\/span><\/h3>\n<p>If you found this exercise valuable, the RWA workshop offers a wide range of other features and best practices that you can explore. For example, you can delve into security best practices, learn how to deploy applications across multiple regions for greater resilience, or optimize your application&#8217;s performance and operational efficiency. Each of these topics is crucial for building a robust, cloud-native application that can scale and perform reliably in production environments.<\/p>\n<h3 class=\"code-line\" dir=\"auto\" data-line=\"156\">Links<\/h3>\n<p class=\"code-line\" dir=\"auto\" data-line=\"156\">Get started with the remainder of the RWA workshop &#8211;&gt; <a title=\"..\/Part1-Tooling\/README.md\" href=\"https:\/\/github.com\/Azure\/reliable-web-app-pattern-java\/blob\/main\/workshop\/Part1-Tooling\/README.md\" data-href=\"..\/Part1-Tooling\/README.md\">Part 1 &#8211; Tooling<\/a><\/p>\n<p dir=\"auto\" data-line=\"156\">Learn more about the <a href=\"https:\/\/learn.microsoft.com\/azure\/architecture\/patterns\/retry\">Retry pattern<\/a><\/p>\n<p dir=\"auto\" data-line=\"156\">Learn more about the <a href=\"https:\/\/learn.microsoft.com\/azure\/architecture\/patterns\/circuit-breaker\">Circuit Breaker pattern<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>As applications migrate to the cloud, they must be designed to handle inevitable failures gracefully. Network issues, service outages, and other transient faults are common in distributed systems. Without proper handling mechanisms, these failures can lead to system instability and poor user experiences. This is why Retry and Circuit Breaker patterns are essential. The Retry [&hellip;]<\/p>\n","protected":false},"author":29534,"featured_media":231426,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-231387","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-java"],"acf":[],"blog_post_summary":"<p>As applications migrate to the cloud, they must be designed to handle inevitable failures gracefully. Network issues, service outages, and other transient faults are common in distributed systems. Without proper handling mechanisms, these failures can lead to system instability and poor user experiences. This is why Retry and Circuit Breaker patterns are essential. The Retry [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/java\/wp-json\/wp\/v2\/posts\/231387","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/java\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/java\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/java\/wp-json\/wp\/v2\/users\/29534"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/java\/wp-json\/wp\/v2\/comments?post=231387"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/java\/wp-json\/wp\/v2\/posts\/231387\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/java\/wp-json\/wp\/v2\/media\/231426"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/java\/wp-json\/wp\/v2\/media?parent=231387"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/java\/wp-json\/wp\/v2\/categories?post=231387"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/java\/wp-json\/wp\/v2\/tags?post=231387"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}