在我们的应用程序中,根据配置(一次或多次),用户只能输入一次或多次进入广告系列。
有一个用户模型,一个Campaigns和campaigns_users模型。如果配置是一次性的,则campaigns_users对于一个用户应该只有一条记录。并且如果该广告系列配置了多次,则同一广告系列的同一用户可能会有很多记录。
由于并发处理,记录被插入了两次。我们已经进行了应用程序级别检查,以确保用户是否输入了广告系列。在某些情况下,两个进程会同时运行,并检查对广告系列的订阅,即使配置是一次指定,用户也会被订阅两次。
class User < ApplicationRecord
def already_subscribed?(campaign)
campaign.campaigns_users.find_by(user_id: id).present?
end
end
在工作中
def perform(user_id, campaign_id)
campaign = Campaign.find_by(id: campaign_id)
user = User.find_by(id: user_id)
return if campaign.config == 'single' && user.already_subscribed?
# Other Logics
end
我已经检查了避免在特定情况下输入两次的解决方案,得到的结果是添加 UNIQUE约束。但是在我的情况下,可以根据配置多次输入用户/一次输入用户。避免创建记录的最佳解决方案是什么?
答案 0 :(得分:0)
我最终使用了Postgres(https://vladmihalcea.com/how-do-postgresql-advisory-locks-work/)的咨询锁。请看看https://github.com/ClosureTree/with_advisory_lock宝石
def perform(user_id, campaign_id)
campaign = Campaign.find_by(id: campaign_id)
user = User.find_by(id: user_id)
# I have used id's as lock name to ensure reducing the time that other threads waiting for accessing this critical section
CampaignUser.with_advisory_lock("#{user.id}-#{campaign.id}")
return if campaign.config == 'single' && user.already_subscribed?
# Other Logics
end
end