В модели заказа пят...
 
Уведомления
Очистить всё

В модели заказа пять колбэков, и импорт старых заказов разослал письма

4 Сообщения
3 Пользователи
2 Реакции
490 Просмотры
Юлия Макарова
Сообщения: 8
Автор темы
Разобрался с блоками бэкенд-разработчица
Присоединился: 2 года назад
[#71]

Rails 8.0, MySQL. Модели заказа лет шесть, колбэки добавляли по одному:

class Order < ApplicationRecord
  after_create :send_confirmation
  after_save :recalculate_customer_stats
  after_save :sync_to_warehouse, if: :saved_change_to_status?
  after_update :notify_manager, if: -> { total > 50_000 }
  before_destroy :restore_stock

  private

  def send_confirmation
    OrderMailer.with(order: self).confirmation.deliver_now
  end
  # остальные такие же короткие
end

Понадобился импорт старых заказов из CSV, около 40 тысяч строк. На стейдже он разослал подтверждения всем, у кого там есть почта, хорошо ещё, что адреса на стейдже подменены. Можно обвесить всё unless importing?, но, по-моему, это путь в никуда. Как бы вы это распутали?


3 ответа
kostya.sokurov
Сообщения: 73
Держит прод бэкенд-разработчик, senior
Присоединился: 4 года назад

Правило, которое меня ни разу не подводило: в колбэках модели только то, без чего данные будут неверными. Письма, синхронизация со складом, уведомление менеджеру - это действия бизнеса, и им место там, где этот бизнес происходит, то есть в явном сценарии оформления заказа:

class PlaceOrder
  def self.call(params)
    order = Order.create!(params)
    OrderMailer.with(order: order).confirmation.deliver_later
    CustomerStatsJob.perform_later(order.customer_id)
    order
  end
end

# контроллер
@order = PlaceOrder.call(order_params)

# импорт создаёт записи, и больше ничего
rows.each { |attrs| Order.create!(attrs) }

Тогда импорту не нужны никакие флаги. Всё за раз не переноси, начни с почты, она больнее всего.


Ответ
GalinaKorneva
Сообщения: 30
Читает чужие PR бэкенд-разработчица
Присоединился: 4 года назад

Если какие-то колбэки останутся, переведи их с after_save на after_commit. Сейчас sync_to_warehouse может отправить на склад заказ из транзакции, которая потом откатится, и склад будет ждать то, чего нет. С джобами то же самое: джобу, поставленную внутри транзакции, воркер может взять раньше, чем запись станет видна, и получит RecordNotFound.


Ответ
Юлия Макарова
Сообщения: 8
Автор темы
Разобрался с блоками бэкенд-разработчица
Присоединился: 2 года назад

Вынесла подтверждение и уведомление менеджеру в PlaceOrder, синхронизацию со складом перевела на after_commit, пересчёт статистики пока остался колбэком, доберусь в следующем спринте. Импорт 40 тысяч заказов на стейдже прошёл за 11 минут и не отправил ни одного письма. Заодно нашлось место в админке, где заказ создавался мимо всего этого, теперь и оно через сервис.


Ответ