Redis
La librería Andreani.ARQ.Redis
fue desarrollada para facilitar la integración de los proyecto de .NET con la base de datos Redis
Prerrequisitos¶
- Instalar Net 6
- Instalar Visual Studio 2022
- Configurar github packages
- Instalar o levantar en docker una instancia de Redis.
Como levantar redis en docker¶
Para levantar redis en docker debemos correr el siguiente comando
docker run -d --name redis-stack -p 6379:6379 -p 8001:8001 redis/redis-stack:latest
Nos levantara un container con Redis al cual podemos conectarnos desde la app mediante
Host: localhost
Port: 6379
Además nos provee de una web, entrando en http://localhost:8001/
que nos permite ver la información almacenada en la base de Redis.
Instalación¶
- Instalar en el proyecto
Application
la dependencia conCore.Redis
dotnet add package Andreani.Arq.Core.Redis
- Instalar en el proyecto
Infreastructure
la dependencia conRedis
dotnet add package Andreani.Arq.Redis
- Instalar en el proyecto
Infreastructure
la dependencia conObservability.ElasticApm.Redis
oObservability.OpenTelemetry.Redis
dotnet add package Andreani.Arq.Observability.ElasticApm.Redis dotnet add package Andreani.Arq.Observability.OpenTelemetry.Redis
Configuración¶
Environment¶
Para configurar la librería debemos agregar la configuración de conexión y demás parámetros en las variables de entorno.
Ejemplo
Redis:
Host: localhost
Port: 6379
InstanceName: test
Opciones de configuración
name | Descripción | Default |
---|---|---|
InstanceName | Nombre de la instancia o aplicación, se utiliza para agregar un prefix a las keys en redis, esto evita tener colisiones con keys de otras apps. | |
Host | Dirección de host del server de redis | localhost |
Port | puerto del server | 6379 |
User | Usuario de acceso al server | |
Password | Password de acceso al server | |
Database | Selecciona la base de datos de redis que va a trabajar la intancias | 0 |
BatchSize | Tamaño de Batch para realizar insert, update o remove masivos | 1000 |
AbsoluteExpirationRelativeToNowSeg | Establece el tiempo de vencimiento de una key en la caché, se establece a partir del momento actual en adelante. El valor ingresado se toma como segundos | |
SlidingExpirationSeg | Obtiene o establece cuánto tiempo una key de caché puede estar inactiva, es decir, sin uso, antes de que se elimine. Esto no extenderá el tiempo de vida de la entrada más allá del vencimiento absoluto (si se establece). El valor ingresado se toma como segundos |
Tip
Si quieren saber más sobre las diferencias entre AbsoluteExpirationRelativeToNow
y SlidingExpirationSeg
pueden ver este post
Injection Dependency¶
En la configuración del services, debemos agregar la siguiente config:
public static IServiceCollection AddInfrastructure(this IServiceCollection services, IConfiguration configuration)
{
//...
services.AddRedis(configuration);
return services;
}
Cómo utilizar la librería¶
Para poder acceder a la implementación debemos inyectar en nuestro código la interface IMemoryDatabase
Ejemplo
private readonly IMemoryDatabase _cache;
public ExampleHandler(IMemoryDatabase cache)
{
_cache = cache;
}
Guardar un elemento en Redis¶
Para almacenar la interface dispone de multiples metodos de set, internamente cada elemento se almacenará como un HSET.
Info
Para saber más que es un HSET ver la docu de redis
Métodos de guardado disponibles¶
void SetString(string key, string value, DistributedCacheEntryOptions options = null);
Task SetStringAsync(string key, string value, DistributedCacheEntryOptions options = null, CancellationToken token = default(CancellationToken));
void Set<T>(string key, T value, DistributedCacheEntryOptions options = null) where T : class;
void Set<T>(Func<T, string> key, IEnumerable<T> value, DistributedCacheEntryOptions options = null) where T : class;
Task SetAsync<T>(Func<T, string> key, IEnumerable<T> value, DistributedCacheEntryOptions options = null) where T : class;
Task SetAsync<T>(string key, T value, DistributedCacheEntryOptions options = null) where T : class;
Task SetAsync(string key, byte[] value, CancellationToken token = default(CancellationToken));
Ejemplo simple¶
Almacenamiento de un objeto en redis
public async Task ExampleSet()
{
var toSave = new AnyObject
{
Id=1,
Name="test"
};
var key = "AlgunaKey";
await _cache.SetAsync(key, toSave);
}
Ejemplo Set Múltiples Objetos¶
Cuando necesitamos volcar muchos datos a redis podemos utilizar el método que provee una estrategia de publicación en batch, para eso podemos enviarle una lista de elementos
public async Task ExampleBulkSet()
{
var toSave = new List<AnyObject>(); // muchos elementos
await _cache.SetAsync((e) => $"AlgunaKey:{e.Id}", toSave);
}
Atención
Esta función (e) => $"AlgunaKey:{e.Id}
significa que por cada elemento de nuestra array vamos generar una key con el id del elemento.
Expiración de key¶
Si hemos configurado una espiración global esta se aplicará en todos los elementos que guardamos, pero podemos configurar para que ignorar la configuración global pasandole una configuración particular:
public async Task ExampleSetWithExp()
{
var toSave = new AnyObject
{
Id=1,
Name="test"
};
var options = new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromDays(1),
SlidingExpiration = TimeSpan.FromHours(1),
};
var key = "AlgunaKey";
await _cache.SetAsync(key, toSave, options);
}
Buscar elementos en Redis¶
Para buscar la interface dispone de multiples métodos de get.
string GetString(string key);
Task<string> GetStringAsync(string key);
Task<T> GetAsync<T>(string key) where T : class;
T Get<T>(string key) where T : class;
IEnumerable<T> GetAll<T>(string pattern = "*") where T : class;
Task<IEnumerable<T>> GetAllAsync<T>(string pattern = "*") where T : class;
IEnumerable<string> GetKeys(string pattern = "*");
Ejemplo Simple¶
Obtener un objeto de redis
public async Task ExampleGet()
{
var key = "AlgunaKey";
var value = await _cache.GetAsync<AnyObject>(key);
//...
}
Tip
Este método recibe el objeto que va a mapear, claramente debe contener la misma estructura que el que se encuentra almacenado.
Obtener todos los elementos de un patrón¶
En caso que necesitemos obtener todos los elementos dado un patrón (regex) de key, por ejemplo, todos los elementos de las key que cumplen con el patron "AlgunaKey"
utilizaremos el método GetAll
public async Task ExampleGetAll()
{
var pattern = "AlgunaKey:*";
var values = await _cache.GetAllAsync<AnyObject>(pattern);
//...
}
Tip
Este método devuelve una lista de elementos.
Info
Para ver más sobre patrones en Redis ver la docu de redis
Obtener las keys de redis¶
Podemos obtener el listado de keys del servidor de redis con el método GetKeys
Eliminar elementos de redis¶
En caso de que no configuremos una expiración o quisiéramos eliminar antes de tiempo una key podemos utilizar los métodos:
void Remove(string key);
Task RemoveAsync(string key, CancellationToken token = default(CancellationToken));
Task RemoveAllWithPatternAsync(string pattern = "*");
Como eliminar múltiples keys¶
Para eliminar múltiples keys debemos utilizar el método RemoveAllWithPatternAsync
.
public async Task ExampleRemove()
{
var pattern = "AlgunaKey:*";
await _cache.RemoveAllWithPatternAsync(pattern);
//...
}
Este método elimina todas las keys que cumplen con el Regex
UseDatabase¶
En el momento que tengamos que hacer algo muy particular con Redis podemos utilizar los métodos:
void UseDatabase(Action<IDatabase> action);
TResult UseDatabase<TResult>(Func<IDatabase, TResult> action) where TResult : class;
Estos métodos inyectan la instancia de base de datos a una función lo que nos permite utilizar funciones nativas de Redis.
Danger
Este método es para último recurso, ya que el uso del mismo nos agrega dependencia directa con el server de redis lo que puede provocar un gran esfuerzo de migración o problemas en el mantenimiento de las aplicaciones.
Info
Pueden encontrar ejemplos en el repositorio de la librería architecture-it/ARQ.Redis