Как обеспечить вставку одиночной записи в рельсы - PullRequest
0 голосов
/ 13 июня 2019

В нашем приложении пользователя можно ввести в кампанию только один или несколько раз в зависимости от конфигурации (один раз или несколько раз).

Здесь есть модель пользователя, кампании и модель 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 .Но в моем случае, пользователь может быть введен несколько раз / один раз в зависимости от конфигурации.Что может быть лучшим решением для избежания создания записи?

1 Ответ

0 голосов
/ 19 июня 2019

Я использовал Консультативный замок от 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...