异步命令和 Task.WhenAny 在 StackExchange.Redis 中等待后的超时异常 [英] Timeout exception after async commands and Task.WhenAny awaits in StackExchange.Redis

查看:32
本文介绍了异步命令和 Task.WhenAny 在 StackExchange.Redis 中等待后的超时异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在经历所谓的超时执行 HGET company:product:settings, inst: 1, queue: 8, qu=0, qs=8, qc=0, wr=0/0, in=79/1 超时异常.

很奇怪,因为在同一台机器上的同一个Redis实例正在存储数据,但它是一个特定的应用程序,抛出了这个异常.更新: 其实就是同一个应用,上面一行是从Redis接收数据.问题在于 HGET.

此外,我已经将多路复用器配置的超时时间增加到 6 秒,但不幸的是.

此外,我检查了 IDatabase 实例具有 IsConnectedtrue 值.

如何解释这些错误消息以及整个超时背后的问题是什么?

一些背景...

我已经成功解决了更改何时某些代码部分获取数据库(即 Multiplexer.GetDatabase())的问题.

虽然多路复用器在每个 AppDomain 都有一个实例,如 StackExchange.Redis 文档中所述,许多控制反转组件正在创建许多 IDatabase 实例在他们自己的代码中.也就是说,IDatabase 实例不是共享的.

实际代码正在执行 ListRightPopLeftPush,然后,它实例化控制组件的反转,该组件在组件实例化期间读取散列键.如果在执行所谓的ListRightPopLeftPush之前实例化整个组件,那么整个HashGet就不会抛出超时异常.

似乎即使当 ListRightPopLeftPush 从其他 IDatabase 实例执行时,它在下一个 IDatabase 实例中产生某种问题,当它来执行读操作.

无论如何,我的修复没有回答这个问题.我刚刚添加了更详细的信息,以便我们找出问题所在及其解决方案.

更新

无论如何,上面的修复"不会修复对 Redis 的进一步读取访问.我在进一步调用中遇到相同的超时异常.现在在异常消息中找到的 in 参数表示 60/1.

解决方案

基于 在聊天中进行了长时间的讨论,并进行了大量挖掘,看起来在一些晦涩的场景中,TPL 在我们执行诸如 .TrySetResult 之类的事情时会劫持专用的阅读器线程(其中:我们经常这样做).如果您进行同步调用,这会导致即时死锁,因为如果它忙于等待任务完成(只能自己完成),则它不可能处理任何套接字数据.我们确实有代码专门用于防止这种情况发生,但看起来解决方法实际上强制它发生在其他一些场景中.这……太可怕了.我会看看我能找到什么.但基本上,问题在于目前,在一些有限的场景中,TaskCompletionSource.TrySetResult 正在赋予 TPL 运行同步延续的权力.这包括 Task.WhenAny.

I'm experiencing the so-called Timeout performing HGET company:product:settings, inst: 1, queue: 8, qu=0, qs=8, qc=0, wr=0/0, in=79/1 timeout exception.

It's strange because the same Redis instance and in the same machine is storing data, but it's a specific application which throws this exception. Update: In fact, the same application, one line above receives data from Redis. The issue is with HGET.

Also, I've increased timeouts on multiplexer configuration to 6 seconds with no luck.

In addition, I've checked that IDatabase instance has IsConnected with true value.

How to interpret these error messages and what's the issue behind the whole timeout?

Some background...

I've successfully fixed the issue changing when some code section gets a database (i.e. multiplexer.GetDatabase()).

While multiplexer has an instance per AppDomain as described in StackExchange.Redis documentation, many inversion of control components are creating many instances of IDatabase in their own code. That is, IDatabase instance isn't shared.

Actual code is performing a ListRightPopLeftPush, and after that, it's instantiating an inversion of control component which reads a hash key during component instatiation. If instantiate the whole component before doing the so-called ListRightPopLeftPush, then the whole HashGet won't throw the timeout exception.

It seems like even when ListRightPopLeftPush is executed from other IDatabase instance, it produces some kind of issue in the next IDatabase instance when it comes to perform read operations.

Anyway, my fix doesn't answer the question. I've just added more detailed info to let us find what's the issue and its own solution.

Update

Anyway, the above "fix" won't fix further read accesses to Redis. I'm getting the same timeout exception in further calls. And now in paramater found in exception's message says 60/1.

解决方案

Based on a long discussion in chat, and a lot of digging, it looks like in some obscure scenarios the TPL is hijacking the dedicated reader thread when we are doing things like .TrySetResult (which: we do often). This causes an instant deadlock if you make a synchronous call, since it can't possibly process any socket data if it is busy waiting for a task to complete (which would only ever be completed by itself). We do actually have code in place specifically to prevent this, but it looks like the workaround actually forces it to happen in some other scenarios. Which... is horrible. I will see what I can find. But basically, the problem is that currently, in some limited scenarios, TaskCompletionSource.TrySetResult is giving power to the TPL to run synchronous continuations. This includes Task.WhenAny.

这篇关于异步命令和 Task.WhenAny 在 StackExchange.Redis 中等待后的超时异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆