Palmer 1.0.0
dotnet add package Palmer --version 1.0.0
NuGet\Install-Package Palmer -Version 1.0.0
<PackageReference Include="Palmer" Version="1.0.0" />
paket add Palmer --version 1.0.0
#r "nuget: Palmer, 1.0.0"
// Install Palmer as a Cake Addin #addin nuget:?package=Palmer&version=1.0.0 // Install Palmer as a Cake Tool #tool nuget:?package=Palmer&version=1.0.0
Palmer
Palmer is a .NET library that presents a fluent-API which makes it easier to write retry logic. Palmer is developed and maintained by Mitch Denny and is released under the MIT license.
How do I get my hands on Palmer?
You can download Palmer is source from GitHub, however as a .NET developer it would be far easier to use NuGet. Simply bring up your package management console and install the package.
Install-Package Palmer
How to do I use Palmer?
Once you have the library installed using Palmer is simple. Just wrap a call to Palmer around the offending code block and it will manage the retry logic for you.
Retry.On<WebException>().For(TimeSpan.FromSeconds(15)).With(context =>
{
// Code that might periodically fail due to connectivity issues.
});
With these few lines of code we are telling Palmer to keep retrying the code for 15 seconds, or until it succeeds. If the code still fails after 15 seconds then a RetryException is thrown which provides the developer with access to the latest exception, and all previously raised exceptions. If the code throws any other exception that exception is allowed to bubble out of Palmer.
Why is it called "Palmer"?
The origins of the library name are tied to the origins of the quote:
"If at first you don't succeed, try, try again." - Thomas H. Palmer
Thomas H. Palmer was an educator who wrote a teachers manual from which this quote was taken. I felt that the quote was appropriate for what the Palmer library does. At the time I named the library I was tempted to name it after W.C. Fields who had an extended version of the quote.
"If at first you don't succeed, try, try again. Then quit. There's no point being a damn fool about it." - W.C. Fields.
This is ultimately why you need to use Palmer. Palmer allows you to succinctly declare retry logic and clearly express under which conditions the code should just give up.
More Examples
Palmer is still a young library and I don't have an exhaustive API reference (feel free to get involved). Rather than provide no documentation I thought I might provide some examples of how you might use Palmer in your code.
###Deadlock Retry This code shows you to example the last raised exception to determine if it was a deadlock. It retries five times before giving up. This demonstrates a "count-based" retry strategy instead of a duration based retry strategy.
Retry.On<SqlException>(handle => (handle.Context.LastException as SqlException).Number == 1205).For(5).With(context =>
{
// Code that might result in a SQL deadlock.
});
###Retry Forever Normally you wouldn't retry forever, but the capability to retry forever is included for completeness.
Retry.On<WebException>().Indefinitely().With(context =>
{
// Code that might throw a web exception.
});
###Non-Exception Failures Some APIs don't throw exceptions. Rather than forcing you to throw an exception when you don't need to, Palmer allows you to write an expression to determine whether a retry is necessary.
var completedSuccessfully = false;
Retry.On(handle => completedSuccessfully).For(5).With(context =>
{
completedSuccessfully = SomeApiThatReturnsTrueOrFailsAsSuccessStatus();
});
Multiple Exceptions
Sometimes the code that you write might throw multiple different exceptions, Palmer allows you to handle this.
Retry.On<WebException>().For(5).AndOn<SqlException>().For(5).With(context =>
{
// Code that might throw a web exception, or a sql exception.
});
In the case above the counts for each exception are independent of each other.
Post Conditions with Until
Post conditions are very similar to detecting non-exception failures. Where they differ is their intended usage. The On/AndOn methods which take predicates are evaluated against every exception or on every run. The predicate specified with the Until method is only evaulated once an exception has been detected. At this point this method could be used to fail after a total number of exceptions has been reached.
Retry
.On<WebException>().Until(handle => handle.Context.Exceptions.Count() > 10)
.AndOn<SqlException().Until(handle => handle.Context.Exceptions.Count() > 10)
.With(context =>
{
// Code that might throw a web exception.
});
Getting Help
If you are using Palmer I would love to hear about it. The easiest way get help is by logging an issue on GitHub. Alternatively you can get me on Twitter at @MitchDenny or via my blog at http://blog.mitchdenny.com.
Contributors
I'm always happy to have someone contribute pull requests to the project. If you do I'll add you to the contributors section here.
- Mitch Denny; primary author of the library.
- Darren Neimke; helped me out debugging some issues with the library.
- Maarten Balliauw; helped me out getting the build work on MyGet.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
.NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
.NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
.NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
MonoAndroid | monoandroid was computed. |
MonoMac | monomac was computed. |
MonoTouch | monotouch was computed. |
Tizen | tizen40 was computed. tizen60 was computed. |
Xamarin.iOS | xamarinios was computed. |
Xamarin.Mac | xamarinmac was computed. |
Xamarin.TVOS | xamarintvos was computed. |
Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- No dependencies.
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Palmer:
Package | Downloads |
---|---|
Mirabeau.uTransporter
An continuous deployment tool for the Umbraco CMS. Synchronizes document types, tab and templates. |
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
1.0.0 | 11,762 | 6/2/2019 |
1.0.0-preview.58 | 326 | 6/1/2019 |
0.1.4724.20297 | 34,419 | 12/7/2012 |
0.1.4724.19830 | 1,389 | 12/7/2012 |
0.1.4724.7256 | 1,683 | 12/7/2012 |
0.1.4723.43045 | 1,523 | 12/7/2012 |
0.1.4723.40614 | 1,360 | 12/6/2012 |