# Getting Started with Murphy This guide will help you install Murphy for Delphi and create your first resilience policies. ## Prerequisites - **Delphi 11 Alexandria** or later - Windows platform (Win32 or Win64) Murphy makes use of modern Delphi features such as inline variables, generics, and anonymous methods. ## Installation ### Using Boss Package Manager (Recommended) The easiest way to install Murphy is using the [Boss package manager](https://github.com/HashLoad/boss): ```bash boss install marcobreveglieri/murphy-delphi ``` Boss will automatically download the library and configure your project paths. ### Manual Installation If you prefer manual installation: 1. Download or clone the Murphy repository from GitHub: ```bash git clone https://github.com/marcobreveglieri/murphy-delphi.git ``` 2. Add the `murphy-delphi/Source` folder to your project's include path: - Open your project in Delphi - Go to **Project > Options > Delphi Compiler > Search path** - Add the full path to `murphy-delphi/Source` 3. Alternatively, add the folder to the IDE's global library path: - Go to **Tools > Options > Language > Delphi > Library** - Add the path to **Library path** for your target platform ## Your First Policy Let's create a simple retry policy that automatically retries failed HTTP requests. ### Step 1: Add the Unit Add the Murphy unit to your uses clause: ```pascal uses Murphy.Policy.Retry; ``` ### Step 2: Create a Retry Policy Create and configure a retry policy using the fluent builder API: ```pascal var RetryPolicy: IRetryPolicy; begin RetryPolicy := TRetryBuilder.Create .Handle(EIdHTTPProtocolException) // Handle HTTP exceptions .Retry(3) // Retry up to 3 times .Wait(TTimeSpan.FromSeconds(1)) // Wait 1 second between retries .Build; end; ``` ### Step 3: Execute Code with the Policy Use the policy to execute your code: ```pascal RetryPolicy.Execute( procedure begin // Your code here - will be automatically retried on failure MakeHttpRequest('https://api.example.com/data'); end); ``` ### Complete Example Here's a complete example: ```pascal unit MyUnit; interface uses System.SysUtils, System.TimeSpan, IdHTTP, IdHTTPProtocolException, Murphy.Policy.Retry; procedure FetchDataWithRetry; implementation procedure FetchDataWithRetry; var RetryPolicy: IRetryPolicy; HTTP: TIdHTTP; Response: string; begin // Create HTTP client HTTP := TIdHTTP.Create(nil); try // Create retry policy RetryPolicy := TRetryBuilder.Create .Handle(EIdHTTPProtocolException) .Retry(3) .Wait(TTimeSpan.FromSeconds(2)) .Build; // Execute with automatic retry RetryPolicy.Execute( procedure begin Response := HTTP.Get('https://api.example.com/data'); WriteLn('Success: ', Response); end); finally HTTP.Free; end; end; end. ``` ## Exploring Other Patterns Murphy includes four resilience patterns. Here are quick examples of each: ### Circuit Breaker Prevent cascading failures by blocking calls to failing services: ```pascal uses Murphy.Policy.CircuitBreaker; var CircuitPolicy: ICircuitBreakerPolicy; begin CircuitPolicy := TCircuitBreakerBuilder.Create .Handle(Exception) .Fail(5) // Open after 5 failures .Within(TTimeSpan.FromSeconds(30)) // Close after 30 seconds .Build; CircuitPolicy.Execute( procedure begin CallExternalService; end); end; ``` ### Fallback Provide alternative results when operations fail: ```pascal uses Murphy.Policy.Fallback; var FallbackPolicy: IFallbackPolicy; Result: string; begin FallbackPolicy := TFallbackBuilder.Create .Handle(Exception) .Fallback(function: string begin Result := 'Cached or default data'; end) .Build; Result := FallbackPolicy.Execute( function: string begin Result := GetDataFromService; end); WriteLn('Result: ', Result); end; ``` ### Rate Limit Control the rate of operations to prevent overload: ```pascal uses Murphy.Policy.RateLimit; var RateLimitPolicy: IRateLimitPolicy; begin RateLimitPolicy := TRateLimitBuilder.Create .Allow(10) // Allow 10 calls .Within(TTimeSpan.FromSeconds(1)) // Per second .Build; // This will throw ERateLimitRejectedException if limit exceeded RateLimitPolicy.Execute( procedure begin MakeApiCall; end); end; ``` ## Working with Exceptions ### Handling Specific Exception Types You can configure policies to handle multiple exception types: ```pascal RetryPolicy := TRetryBuilder.Create .Handle(EIdHTTPProtocolException) .Handle(EIdSocketError) .Handle(EIdConnClosedGracefully) .Retry(3) .Build; ``` ### Catching Exceptions from Policies Policies re-raise exceptions after exhausting retries or when not handled: ```pascal try RetryPolicy.Execute( procedure begin MakeRequest; end); except on E: EIdHTTPProtocolException do WriteLn('Request failed after retries: ', E.Message); end; ``` ## Best Practices for Getting Started 1. **Start Simple** - Begin with a single pattern (e.g., Retry) before combining multiple patterns 2. **Use Specific Exceptions** - Handle specific exception types rather than catching all exceptions 3. **Configure Appropriately** - Adjust retry counts and delays based on your specific use case 4. **Test Your Policies** - Enable test mode (`MurphyTestModeEnabled := True`) for unit testing 5. **Monitor Behavior** - Log or track when policies are triggered to understand system behavior ## Common Scenarios ### Scenario 1: Database Connection Retry ```pascal RetryPolicy := TRetryBuilder.Create .Handle(EDatabaseError) .Retry(3) .Wait(TTimeSpan.FromSeconds(1)) .Build; RetryPolicy.Execute( procedure begin Database.Connect; end); ``` ### Scenario 2: API with Fallback ```pascal var FallbackPolicy: IFallbackPolicy; Data: TJSONObject; begin FallbackPolicy := TFallbackBuilder.Create .Handle(Exception) .Fallback(function: TJSONObject begin Result := GetCachedData; end) .Build; Data := FallbackPolicy.Execute( function: TJSONObject begin Result := FetchDataFromAPI; end); end; ``` ### Scenario 3: Rate-Limited API Client ```pascal var RateLimitPolicy: IRateLimitPolicy; I: Integer; begin RateLimitPolicy := TRateLimitBuilder.Create .Allow(100) // 100 requests .Within(TTimeSpan.FromMinutes(1)) // Per minute .Build; for I := 1 to 1000 do begin try RateLimitPolicy.Execute( procedure begin MakeAPIRequest(I); end); except on E: ERateLimitRejectedException do begin WriteLn('Rate limit exceeded, waiting...'); Sleep(1000); end; end; end; end; ``` ## Demo Application Murphy includes a comprehensive demo application with examples for all patterns. You can find it in the `Demos/00_Primer` folder: - **Samples.Retry.pas** - Retry pattern examples - **Samples.CircuitBreaker.pas** - Circuit breaker examples - **Samples.Fallback.pas** - Fallback examples - **Samples.RateLimit.pas** - Rate limit examples Run the demo to see the patterns in action and explore the code for more examples. ## Next Steps Now that you've learned the basics: - **Deep Dive**: Read the [Pattern Guides](README.md#pattern-guides) for comprehensive examples - **API Reference**: Explore the [API Reference](API-Reference/README.md) for detailed documentation - **Advanced Usage**: Learn about [Combining Patterns](Patterns/Combining-Patterns.md) - **Best Practices**: Review [Best Practices](Advanced/Best-Practices.md) for production use ## Troubleshooting ### "Unit not found" error Make sure the `murphy-delphi/Source` folder is in your project's search path or library path. ### Compilation errors about inline variables Murphy requires Delphi 11 Alexandria or later. Check your Delphi version. ### Policies not working as expected Enable test mode and verify your exception types are correct. Check the [Testing Guide](Advanced/Testing.md) for more information. --- [← Introduction](01-Introduction.md) | [Back to Index](README.md) | [Chaos Engineering Basics →](03-Chaos-Engineering.md)