Skip to content
Howard van Rooijen By Howard van Rooijen Co-Founder
Extending Endjin.Retry with custom Retry Policies

Update: This project has been replaced by Corvus.Retry.

Someone tweeted @endjin this week to ask if we were still supporting our Endjin.Retry framework; they asked because they were worried it had been abandoned because it had only had 6 minor commits in 2014. I replied to confirm that we have not abandoned this project in the slightest, in fact it's one of our most used, core bits of IP (along with Endjin.Composition), that we use in practically every project we develop whether it's related specifically to Azure or not. We have found that it is easier to extend Endjin.Retry, through its IRetryPolicy and IRetryStrategy inside the consuming project rather than pollute the core library – this means all of these customisations happen in our private project repos, not in the public Endjin.Retry repo.

Below are a series of examples of custom retry policies we've implemented in various projects:

HttpRequestExceptionRetryPolicy

This a very simple retry policy that will retry if a HttpRequestException is encountered. A good general purpose transient HTTP error retry strategy

#region Using Directives

using System;
using System.Net.Http;

using Endjin.Core.Retry.Policies;

#endregion

public class HttpRequestExceptionRetryPolicy : IRetryPolicy
{
    public bool CanRetry(Exception ex)
    {
        return ex is HttpRequestException;
    }
}

DoNotRetryOnConflictPolicy

This retry policy was specifically designed to work with the Azure Storage SDK will retry on any exception except for a HTTP 409 Conflict status code – a scenario whereby the resource you're trying to create already exists.


#region Using Directives

using System;

using Endjin.Core.Retry.Policies;

using Microsoft.WindowsAzure.Storage;

#endregion 

public class DoNotRetryOnConflictPolicy : IRetryPolicy
{
    public bool CanRetry(Exception exception)
    {
        var storageException = exception as StorageException;

        if (storageException != null && storageException.RequestInformation.HttpStatusCode == 409)
        {
            return false;
        }

        return true;
    }
}

DoNotRetryOn304NotModified

Similar to the previous policy, this retry policy will retry except for a HTTP 304 Not Modified status code.

#region Using Directives

using System;
using System.Net;

using Endjin.Core.Retry.Policies;

using Microsoft.WindowsAzure.Storage;

#endregion

public class DoNotRetryOn304NotModified : IRetryPolicy
{
    public bool CanRetry(Exception exception)
    {
        var storageException = exception as StorageException;

        if (storageException == null)
        {
            return true;
        }

        return storageException.RequestInformation.HttpStatusCode != (int)HttpStatusCode.NotModified;
    }
}

StorageWriteExceptionRetryPolicy

The following retry policy was created to retry except in the event of a HTTP Protocol error or a HTTP 409 Conflict status code

#region Using Directives

using System;
using System.Diagnostics;
using System.Net;

using Endjin.Core.Retry.Policies;
using Endjin.Kpi.Core.Extensions;

using Microsoft.WindowsAzure.Storage;

#endregion

public class StorageWriteExceptionRetryPolicy : IRetryPolicy
{
    public bool CanRetry(Exception ex)
    {
        Trace.TraceError(ex.GetFullExceptionMessage());

        var we = ex as WebException;
        
        if (we != null && we.Status == WebExceptionStatus.ProtocolError)
        {
            return false;
        }

        var se = ex as StorageException;

        if (se != null && se.RequestInformation.HttpStatusCode == (int)HttpStatusCode.Conflict)
        {
            return false;
        }

        return ex is LeaseException;
    }
}

DoNotRetryOnLeaseAcquisitionUnsuccessfulPolicy

This retry policy is part of our Endjin.Leasing framework, which implements Mutex operations over Azure Blob Storage and will retry unless a LeaseAcquisitionUnsuccessfulException is detected, and would enable a scenario whereby you'd have a series of competing actors who want perform an action against a specific resource, the first to obtain the Mutex wins and the other actors fail fast.

#region Using Directives

using System;

using Endjin.Core.Retry.Policies;

#endregion 

public class DoNotRetryOnLeaseAcquisitionUnsuccessfulPolicy : IRetryPolicy
{
    public bool CanRetry(Exception exception)
    {
        var storageException = exception as LeaseAcquisitionUnsuccessfulException;

        if (storageException != null)
        {
            return false;
        }

        return true;
    }
}

RetryUntilLeaseAcquiredPolicy

This retry policy is also part of our Endjin.Leasing framework but enables the opposite scenario than the previous policy; if multiple actors want to perform an action on a particular resource, the should retry until the obtain their Mutex:

#region Using Directives

using System;

using Endjin.Core.Retry.Policies;
    
#endregion

public class RetryUntilLeaseAcquiredPolicy : IRetryPolicy
{
    public bool CanRetry(Exception exception)
    {
        var actualException = exception as LeaseAcquisitionUnsuccessfulException;

        return actualException != null;
    }
}

Hopefully these examples show how easy it is to implement your own retry policies, which nicely encapsulate your success and failure conditions.

The Introduction to Rx.NET 2nd Edition (2024) Book, by Ian Griffiths & Lee Campbell, is now available to download for FREE.

@HowardvRooijen

Programming C# 12 Book, by Ian Griffiths, published by O'Reilly Media, is now available to buy.

Sign up to Azure Weekly to receive Azure related news and articles direct to your inbox every Sunday, or follow @azureweekly on Twitter.

Howard van Rooijen

Co-Founder

Howard van Rooijen

Howard spent 10 years as a technology consultant helping some of the UK's best known organisations work smarter, before founding endjin in 2010. He's a Microsoft ScaleUp Mentor, and a Microsoft MVP for Azure and Developer Technologies, and helps small teams achieve big things using data, AI and Microsoft Azure.