sozsoft-platform/api/modules/Sozsoft.Languages/Sozsoft.Languages.Domain/Caching/DistributedCacheCleaner.cs
2026-10-05 15:58:59 +03:00

97 lines
3.5 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Options;
using StackExchange.Redis;
using Sozsoft.Languages.Localization;
using Volo.Abp.Caching;
using Volo.Abp.DependencyInjection;
namespace Sozsoft.Languages.Caching;
/// <summary>
/// Uygulamanın dağıtık önbelleğini boşaltır. <c>FLUSHALL</c> yerine yalnızca bu uygulamanın anahtarlarını
/// siler: Redis başka bir uygulama ya da ortamla paylaşılıyorsa onların verisine dokunulmaz.
/// Bağlantı süreç başına tektir; her çağrıda yeni bağlantı açmak bağlantı sızdırıyordu.
/// </summary>
public class DistributedCacheCleaner : ISingletonDependency, IDisposable
{
private const int BatchSize = 500;
private readonly Lazy<ConnectionMultiplexer> _connection;
private readonly string[] _keyPatterns;
private readonly IDatabaseResourceLocalizer _localizer;
public DistributedCacheCleaner(
IConfiguration configuration,
IOptions<AbpDistributedCacheOptions> cacheOptions,
IDatabaseResourceLocalizer localizer)
{
_localizer = localizer;
_connection = new Lazy<ConnectionMultiplexer>(
() => ConnectionMultiplexer.Connect(configuration["Redis:Configuration"]!));
// ABP iki biçimde yazar: IDistributedCache<T> anahtarı [t:{kiracı},]c:{önbellek},k:{KeyPrefix}{anahtar},
// bellek içi tanım önbelleklerinin damgası ise doğrudan {KeyPrefix}_Abp...Stamp. Host "Platform",
// DbMigrator "Platform:" öneki kullanır; ':' atılınca desenler iki sürecin anahtarlarını da kapsar.
var prefix = (cacheOptions.Value.KeyPrefix ?? string.Empty).TrimEnd(':');
_keyPatterns = [$"{prefix}*", $"*,k:{prefix}*"];
}
/// <returns>Silinen anahtar sayısı.</returns>
public async Task<long> ClearAsync()
{
var connection = _connection.Value;
var database = connection.GetDatabase();
long removed = 0;
foreach (var endpoint in connection.GetEndPoints())
{
var server = connection.GetServer(endpoint);
if (server.IsReplica || !server.IsConnected)
{
continue;
}
foreach (var pattern in _keyPatterns)
{
var batch = new List<RedisKey>(BatchSize);
await foreach (var key in server.KeysAsync(database.Database, pattern, BatchSize))
{
batch.Add(key);
if (batch.Count == BatchSize)
{
removed += await DeleteAsync(database, batch);
batch.Clear();
}
}
removed += await DeleteAsync(database, batch);
}
}
// Dil sözlüğünün süreç içi kopyası Redis'te değildir; temizlik onu da kapsar.
_localizer.ClearLocalCache();
return removed;
}
// Anahtarlar tek tek silinir: çok anahtarlı DEL, cluster'da farklı slot'lara düşen anahtarları reddeder.
private static async Task<long> DeleteAsync(IDatabase database, List<RedisKey> keys)
{
var results = await Task.WhenAll(keys.Select(key => database.KeyDeleteAsync(key)));
return results.Count(deleted => deleted);
}
public void Dispose()
{
if (_connection.IsValueCreated)
{
_connection.Value.Dispose();
}
GC.SuppressFinalize(this);
}
}