当使用EF Core2.1 DbContext时,在Azure QueueTrigger函数中使用PK违规异常。猜测是由于DbContext不是线程安全的性质,以及Azure函数并行运行不同的实例。我读过很多书,但我找不到解决这个问题的好办法。
下面是我的场景(生产者-消费者模式):
我有一个计划的Azure函数,它调用API从不同的外部系统获取项目。为了获取项目所需的所有信息,我需要对其他外部服务运行不同的查询,因此我将它与另一个Azure函数分离,因此计划的函数将每个项目的消息排成队列,作为“同步项目ID 101”。
每当消息排队时,另一个QueueTrigger函数就会触发,因此,它意味着不同的实例在并行中运行。此函数必须收集特定项目的所有数据,这意味着更多对其他外部服务/API的调用,以(某种形式)聚合有关项目的所有信息。这样做很好,因为我可以并行处理多个项目,如果需要的话,我可以扩展功能。
一旦我获得了所有这些项目信息,我想使用EF将其保存在SQL中(问题来了)
项目数据包括项目中的用户,每个用户都有一个特定的GUID作为PK (来自外部系统)。这意味着我可以在不同的函数实例中有重复的用户I,这就是问题所在,因为当我试图在SQL Table中持久化用户信息时,我可以得到PK复制异常,因为多个函数实例可以同时尝试插入同一个用户(当实例A检查用户是否存在时,它会变成假的,但是另一个实例B实际上是在添加这个用户,所以当实例A尝试插入时,它就失败了)。
我想我可以以某种方式锁定DbContext,但不确定是否好,因为我也有一个网站对SQL进行查询(目前为只读查询,但将来也可能进行更新)。
另一个想法可以是将整个Project发送到另一个队列/ Blob文件,并在Singleton模式下具有另一个函数,将数据插入到SQL中。
我创建了这个项目,简化了我的场景,但是足够重现问题和理解问题。https://github.com/luismanez/queuetrigger-efcore-multithreading
还有其他的想法或推荐的方法吗?(如果发现更好的东西,可以更改体系结构)
非常感谢!
发布于 2018-10-24 10:45:19
一种“更容易”的方法是在数据库中进行某种类型的插入。有一个示例说明如何使用EF:https://www.flexlabs.org/2018/02/adding-upsert-support-for-entity-framework-core来实现这一点。
https://stackoverflow.com/questions/52830562
复制相似问题