Skip to content

Redis Cache

Azure Cache for Redis is used across all Microtec environments for distributed caching, session data, and ASP.NET Core DataProtection key ring storage. All Redis connections use SSL on port 10000.


Redis Usage Patterns

Use CaseDescriptionKey Pattern
Session cachingUser session data (JWT claims cache)session:{userId}:{tenantId}
DataProtection keysASP.NET Core key ring (cookie encryption)DataProtection-Keys
Distributed cacheFrequently-read reference data (dropdowns, lookups)cache:{tenantId}:{entity}:{id}
Output cachingHTTP response caching for read-heavy endpointsoc:{route-hash}
Idempotency keysPrevent duplicate command processingidempotency:{requestId}

Per-Environment Redis Instances

EnvironmentHostnamePortSKU
devmic-erp-be-dev-redis.redis.cache.windows.net10000Basic C0
stagemic-erp-be-stage-redis.uksouth.redis.azure.net10000Standard C1
preprodmic-erp-be-preprod-redis.uksouth.redis.azure.net10000Standard C1
uatmic-erp-be-uat-redis.uksouth.redis.azure.net10000Standard C1
productionmic-erp-be-prod-redis.uksouth.redis.azure.net10000Premium P1

Production Premium SKU

The production Redis instance uses the Premium P1 SKU which provides:

  • Redis Cluster for higher throughput
  • Geo-replication (secondary replica in West Europe)
  • VNet injection (instead of private endpoint)
  • Redis persistence (RDB snapshots every hour)

Connection String

Format

{hostname}:{port},password={password},ssl=True,abortConnect=False,connectTimeout=5000,syncTimeout=5000

Stage example:

mic-erp-be-stage-redis.uksouth.redis.azure.net:10000,password=<from-kv>,ssl=True,abortConnect=False

SSL=True and Port 10000 Are Mandatory

Azure Cache for Redis enforces SSL. Non-SSL port 6379 is disabled on all instances. Always specify:

  • ssl=True in the connection string
  • Port 10000 (not 6379)

Without these, connections will fail silently or with a cryptic timeout error.

Key Vault Secret

KV Secret name: RedisConfiguration--Password
App config key: RedisConfiguration:Password

Full connection string is assembled in the shared Microtec.Web.Core package:
  "{host}:{port},password={KV password},ssl=True,abortConnect=False"

.NET Integration

StackExchange.Redis Registration

csharp
// Microtec.Web.Core / Extensions/CacheExtensions.cs
public static IServiceCollection AddMicrotecCache(
    this IServiceCollection services,
    IConfiguration configuration)
{
    var redisConnectionString = configuration["RedisConfiguration:ConnectionString"]!;

    services.AddStackExchangeRedisCache(options =>
    {
        options.Configuration = redisConnectionString;
        options.InstanceName = "MicrotecERP:";
    });

    services.AddSingleton<IConnectionMultiplexer>(
        ConnectionMultiplexer.Connect(redisConnectionString));

    return services;
}

DataProtection Key Ring

ASP.NET Core DataProtection keys are persisted to Redis so all Container App replicas share the same key ring (required for cookie decryption across replicas):

csharp
services.AddDataProtection()
    .PersistKeysToStackExchangeRedis(
        ConnectionMultiplexer.Connect(redisConnectionString),
        "DataProtection-Keys")
    .SetApplicationName("MicrotecERP")
    .SetDefaultKeyLifetime(TimeSpan.FromDays(90));

DataProtection Keys Are Machine-Specific by Default

Without the Redis key ring persistence, each Container App replica generates its own DataProtection key. Users whose session cookie was encrypted by replica A cannot be decrypted by replica B, causing continuous logouts. Always use the shared Redis key ring in environments with more than one replica.

Known gotcha: DataProtection keys in Redis are encrypted with a machine-specific key. If you flush Redis and the original keys are gone, existing session cookies cannot be decrypted. Users must re-authenticate. This is expected behaviour during a Redis flush.


Cache Key Strategies

Tenant Isolation

All application-level cache keys are prefixed with the tenant ID to prevent cross-tenant data leakage:

csharp
public class TenantAwareCacheService : ICacheService
{
    private readonly IDistributedCache _cache;
    private readonly ITenantProvider _tenantProvider;

    public async Task<T?> GetAsync<T>(string key, CancellationToken ct = default)
    {
        var tenantKey = $"{_tenantProvider.TenantId}:{key}";
        var bytes = await _cache.GetAsync(tenantKey, ct);
        return bytes is null ? default : JsonSerializer.Deserialize<T>(bytes);
    }
}

TTL Conventions

Data TypeTTLRationale
User session8 hoursAlign with business day working session
Reference data (dropdowns)30 minutesRefresh frequently enough for config changes
Report results5 minutesBalance freshness vs DB load
Idempotency keys24 hoursCover duplicate submission window
DataProtection keys90 daysSet by SetDefaultKeyLifetime

Monitoring Redis

Azure Portal Metrics

Key metrics to watch in Azure Monitor for each Redis instance:

MetricHealthy RangeAlert Threshold
Server Load< 60%> 80% for 5 min
Used Memory< 70%> 85%
Cache Hits> 80% hit rate< 50% (cache not effective)
Connected Clients< 500> 900 (SKU limit approaching)
Evicted Keys0> 100/min (memory pressure)

CLI Diagnostics

bash
# Connection test (from inside private VNet / jump box)
redis-cli \
  -h mic-erp-be-stage-redis.uksouth.redis.azure.net \
  -p 10000 \
  -a "${REDIS_PWD}" \
  --tls PING

# Key count by prefix
redis-cli --tls -h ... -p 10000 -a ... KEYS "MicrotecERP:*" | wc -l

# Memory info
redis-cli --tls -h ... -p 10000 -a ... INFO memory

# Check DataProtection keys
redis-cli --tls -h ... -p 10000 -a ... KEYS "DataProtection-Keys*"

Redis Flush (Emergency Procedure)

Impact of FLUSHALL

Flushing Redis clears:

  1. All session caches → all users are logged out
  2. DataProtection keys → all existing cookies are invalidated (logouts)
  3. All distributed cache → increased DB load on next requests
  4. Idempotency keys → duplicate requests may be processed

Only flush Redis when directed by an on-call incident commander during a P1 incident. Notify the support team before executing.

bash
REDIS_PWD=$(az keyvault secret show \
  --vault-name mic-erp-stg-kv \
  --name "RedisConfiguration--Password" \
  --query value -o tsv)

redis-cli \
  -h mic-erp-be-stage-redis.uksouth.redis.azure.net \
  -p 10000 \
  -a "${REDIS_PWD}" \
  --tls FLUSHALL ASYNC

Use FLUSHALL ASYNC (not FLUSHALL) to avoid blocking the Redis server during the flush operation.

Internal Documentation — Microtec Platform Team