# Redis

Package: MassTransit.Redis (opens new window)

Redis is a very popular key-value store, which is known for being very fast. To support Redis, MassTransit uses the StackExchange.Redis library.

WARNING

Redis only supports event correlation by CorrelationId, it does not support queries. If a saga uses expression-based correlation, a NotImplementedByDesignException will be thrown.

Storing a saga in Redis requires an additional interface, ISagaVersion, which has a Version property used for optimistic concurrency. An example saga is shown below.

namespace PersistedSaga
{
    using System;
    using MassTransit.Saga;
    using Automatonymous;

    public class OrderState :
        SagaStateMachineInstance,
        ISagaVersion
    {
        public Guid CorrelationId { get; set; }
        public string CurrentState { get; set; }

        public DateTime? OrderDate { get; set; }

        public int Version { get; set; }
    }
}

# Configuration

To configure Redis as the saga repository for a saga, use the code shown below using the AddMassTransit container extension. This will configure Redis to connect to the local Redis instance on the default port using Optimistic concurrency. This will also store the ConnectionMultiplexer in the container as a single instance, which will be disposed by the container.

namespace RedisSagaContainer
{
    using MassTransit;
    using Microsoft.Extensions.DependencyInjection;
    using PersistedSaga;

    public class Program
    {
        public static void Main()
        {
            var services = new ServiceCollection();

            services.AddMassTransit(x =>
            {
                const string configurationString = "127.0.0.1";

                x.AddSagaStateMachine<OrderStateMachine, OrderState>()
                    .RedisRepository(configurationString);
            });
        }
    }
}

The example below includes all the configuration options, in cases where additional settings are required.

namespace RedisSagaContainerConfiguration
{
    using System;
    using MassTransit;
    using MassTransit.RedisIntegration;
    using Microsoft.Extensions.DependencyInjection;
    using PersistedSaga;

    public class Program
    {
        public static void Main()
        {
            var services = new ServiceCollection();

            services.AddMassTransit(x =>
            {
                const string configurationString = "127.0.0.1";

                x.AddSagaStateMachine<OrderStateMachine, OrderState>()
                    .RedisRepository(r =>
                    {
                        r.DatabaseConfiguration(configurationString);

                        // Default is Optimistic
                        r.ConcurrencyMode = ConcurrencyMode.Pessimistic;

                        // Optional, prefix each saga instance key with the string specified
                        // resulting dev:c6cfd285-80b2-4c12-bcd3-56a00d994736
                        r.KeyPrefix = "dev";

                        // Optional, to customize the lock key
                        r.LockSuffix = "-lockage";

                        // Optional, the default is 30 seconds
                        r.LockTimeout = TimeSpan.FromSeconds(90);
                    });;
            });
        }
    }
}

The container extension will register the saga repository in the container. For more details on container configuration, review the container configuration section of the documentation.

# Concurrency

Redis supports both Optimistic (default) and Pessimistic concurrency.

In optimistic mode, the saga instance is not locked before reading, which can ultimately lead to a write conflict if the instance was updated by another message. The Version property is used to compare that the update would not overwrite a previous update. It is recommended that a retry policy is configured (using UseMessageRetry, see the exceptions documentation).

Pessimistic concurrency uses the Redis lock mechanism. During the message processing, the repository will lock the saga instance before reading it, so that any concurrent attempts to lock the same instance will wait until the current message has completed or the lock timeout expires.