namespace ThingsGateway.NewLife.Caching;

/// <summary>分布式缓存架构服务。提供基础缓存及队列服务</summary>
/// <remarks>
/// 文档 https://newlifex.com/core/icacheprovider
/// 根据实际开发经验，即使在分布式系统中，也有大量的数据是不需要跨进程共享的，因此本接口提供了两级缓存。
/// 进程内缓存使用<see cref="InnerCache"/>，可以规避对象序列化成本，跨进程缓存使用<see cref="Cache"/>。
/// 借助该缓存架构，可以实现各功能模块跨进程共享数据，分布式部署时可用Redis，需要考虑序列化成本。
/// 
/// 使用队列时，可根据是否设置消费组来决定使用简单队列还是完整队列。
/// 简单队列（如RedisQueue）可用作命令队列，Topic很多，但几乎没有消息。
/// 完整队列（如RedisStream）可用作消息队列，Topic很少，但消息很多，并且支持多消费组。
/// </remarks>
public interface ICacheProvider
{
    /// <summary>全局缓存。各功能模块跨进程共享数据，分布式部署时可用Redis，需要考虑序列化成本。默认单机使用内存缓存</summary>
    ICache Cache { get; set; }

    /// <summary>应用内本地缓存。默认内存缓存，无需考虑对象序列化成本，缺点是不支持跨进程共享数据</summary>
    ICache InnerCache { get; set; }

    /// <summary>获取队列。各功能模块跨进程共用的队列</summary>
    /// <remarks>
    /// 使用队列时，可根据是否设置消费组来决定使用简单队列还是完整队列。
    /// 简单队列（如RedisQueue）可用作命令队列，Topic很多，但几乎没有消息。
    /// 完整队列（如RedisStream）可用作消息队列，Topic很少，但消息很多，并且支持多消费组。
    /// </remarks>
    /// <typeparam name="T">消息类型。用于消息生产者时，可指定为Object</typeparam>
    /// <param name="topic">主题</param>
    /// <param name="group">消费组。未指定消费组时使用简单队列（如RedisQueue），指定消费组时使用完整队列（如RedisStream）</param>
    /// <returns></returns>
    IProducerConsumer<T> GetQueue<T>(String topic, String? group = null);

    /// <summary>获取内部队列。默认内存队列</summary>
    /// <typeparam name="T">消息类型</typeparam>
    /// <param name="topic">主题</param>
    /// <returns></returns>
    IProducerConsumer<T> GetInnerQueue<T>(String topic);

    /// <summary>申请分布式锁</summary>
    /// <remarks>
    /// 一般实现为Redis分布式锁，申请锁的具体表现为锁定某个key，锁维持时间为msTimeout，遇到冲突时等待msTimeout时间。
    /// 如果在等待时间内获得锁，则返回一个IDisposable对象，离开using代码块时自动释放锁。
    /// 如果在等待时间内没有获得锁，则抛出异常，需要自己处理锁冲突的情况。
    /// 
    /// 如果希望指定不同的维持时间和等待时间，可以使用<see cref="ICache"/>接口的<see cref="ICache.AcquireLock(String, Int32, Int32, Boolean)"/>方法。
    /// </remarks>
    /// <param name="lockKey">要锁定的键值。建议加上应用模块等前缀以避免冲突</param>
    /// <param name="msTimeout">遇到冲突时等待的最大时间，同时也是锁维持的时间</param>
    /// <returns></returns>
    IDisposable? AcquireLock(String lockKey, Int32 msTimeout);
}