首页 > 解决方案 > Redis缓存InvalidOperationException:读取完成后不允许读取

问题描述

我有一个不断将数据插入redis的网络作业我有另一个时间触发功能,可以在每5分钟后从同一个redis缓存中读取数据。

  public static void ProcessData([TimerTrigger("0 */5 * * * *")] TimerInfo myTimer)
        {
            var newCacheclient = new RedisCacheClient(Program.spRedisCacheConnectionPoolMgr, Program.serializer, Program.redisConfiguration).Db0;

            var cachedData = newCacheclient.GetAsync<List<MyObject>>("mydata").Result;

执行 10-15 分钟后,时间触发功能出现错误。有人知道如何解决这个问题吗?

InvalidOperationException:阅读器完成后不允许阅读。

我也向 github 提出了同样的问题。

nuget 版本详细信息 - 在此处输入图像描述

错误堆栈 - 内部异常 1:

InvalidOperationException: Reading is not allowed after reader was completed.


   at System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification)
   at MyData.Functions.ExecuteTrade(TimerInfo myTimer) in C:\Users\\Functions.cs:line 27
   at Microsoft.Azure.WebJobs.Host.Executors.VoidMethodInvoker`1.InvokeAsync(TReflected instance, Object[] arguments)
   at Microsoft.Azure.WebJobs.Host.Executors.FunctionInvoker`1.<InvokeAsync>d__0.MoveNext()
   
   at System.IO.Pipelines.ThrowHelper.ThrowInvalidOperationException_NoReadingAllowed()
   at System.IO.Pipelines.Pipe.AdvanceReader(SequencePosition& consumed, SequencePosition& examined)
   at System.IO.Pipelines.Pipe.DefaultPipeReader.AdvanceTo(SequencePosition consumed, SequencePosition examined)
   at StackExchange.Redis.PhysicalConnection.<ReadFromPipe>d__110.MoveNext() in /_/src/StackExchange.Redis/PhysicalConnection.cs:line 1495
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at StackExchange.Redis.Extensions.Core.Implementations.RedisDatabase.<GetAsync>d__14`1.MoveNext()

标签: c#azurec#-4.0redisstackexchange.redis

解决方案


我在代码中看到了几个问题:

  1. 您应该重复使用相同的 redis 客户端实例,以避免与 redis 服务器的 tcp 连接过多。
  2. 不要使用.Result以避免阻塞当前线程。将方法更新为异步并在 GetAsync 上使用 await。
  3. 确保不要在缓存条目中存储大对象(在这种情况下List<MyObject>不应该是大列表)

以下是更新后的代码:

        private static readonly IRedisCacheClient redisCacheClient = new RedisCacheClient(Program.spRedisCacheConnectionPoolMgr, Program.serializer, Program.redisConfiguration);
        
        public static async Task ProcessData([TimerTrigger("0 */5 * * * *")] TimerInfo myTimer)
        {
            var redisDB = redisCacheClient.Db0;
            var cachedData = await redisDB.GetAsync<List<MyObject>>("mydata").ConfigureAwait(false);
        }

推荐阅读