최근 자신이 Resolve한 rails 코드의 Rollbar가 가르쳐 준 에러에 대해 정리

10090 단어 롤바루비Rails6

이 기사에서 쓰기



미끄러져 쓰기 시작한 어드벤트 캘린더용 기사.
기본적으로 자신이 소속하는 팀에서는 Rollbar의 에러는 크리티컬한 것 이외는 대응이 별로 되지 않았지만,
지난 1개월 반 정도 개인적으로 트라이로서 의식적으로 Rollbar로부터 통지를 받은 에러를 수정하기 위해 다른 태스크와의 공수를 조정하면서 일한 결과 어떤 에러가 있었는지 정리한다.
기본적으로 모두 코드 리뷰를 통과하는 이상, 어떤 곳이 리뷰에서 잡을 수 없었던 에러였는지도 검토하면 알 수 있을 것이다.

참조 할 수 없게 될 수있는 값에 대한 참조가 남아있을 때 undefind 오류



케이스 1



배경



sidekiq에 맡기고 있는 메일 송신 처리에서, 큐가 모여 실제로 처리가 불릴 때까지의 사이에 Mailer에 기재되어 있는 처리에서 참조하고 있는 값이 삭제되었다.
Mailer로 보내는 곳이 사용자가 등록한 메일 주소였지만, 큐에 모이는 동안 탈퇴 처리가 되어 버리면, 등록하고 있는 어카운트 정보를 물리 삭제하고 있기 때문에, 참조 에러가 발생하고 있다 했다.
희귀한 케이스이지만 기분 나빴기 때문에 수정했다.

대응 내용



Mailer에서 후속 처리가 불리지 않도록 조기 리턴시켰다.
return unless user_account.present?

사례 2



배경



Oauth 인증의 처리로, 반드시 값이 들어가는 것이 보증되지 않는 변수를 읽고 있었다.

대응 내용



에러를 일으키는 것이 아니라, 다른 페이지(다음 액션을 촉구하는 것)에 날리는 것이 바람직했기 때문에, &.(ボッチ演算子)nil 결정하고 대응
case origin&.path
when nil
  # ここにどうすべきかの処理を記載
when '/hoge'

케이스 3



배경



관련 모델의 after_create 로 불리는 처리에 시간이 걸리는 일이 있어, 가끔 후속하는 처리의 변수 참조가 사이에 맞지 않아, id(프라이머리 키)에의 참조 에러가 일어나고 있었다.
# 記載されているコードはイメージを残す為の例です。実際に動いてるコードではありません。
# roomとtopicは1対1. topicとdiscussionsは1対多
room = Room.find_or_initialize_by(user: current_user, name: 'もくもくテスト部屋')
if room.new_record?
  room.save!
  topic = Topic.new(room: room)
  topic.discussions.build(comment: comment, user: current_user)
  topic.save!  # discussionsのafter_createの非同期処理に時間がかかる時があり、
else
  topic = room.topic
end
redirect_to topic_path(topic) # ここでtopic.id への参照エラーが発生

대응 내용



Transaction으로 둘러싸여, 레코드의 작성 상태를 보증하면서, 관련 모델과는 별도로, 참조되고 있는 변수를 먼저 create 해 버리게 했다.
room = Room.find_or_initialize_by(user: current_user, name: 'もくもくテスト部屋')
topic = if room.new_record?
          create_topic_with(room, comment)
        else
          room.topic
        end
redirect_to topic_path(topic)

def create_topic_with(room, comment)
  # どこかで例外が発生したとしても、Transactionで囲っているのでRollbackされるので安全。
  Room.transaction do
    room.save!
    topic = Topic.create!(room: room) # 先にcreateしてしまうようにした
    topic.discussions.build(comment: comment, user: current_user)
    topic.save!
    topic
  end
end

ActiveRecord::RecordNotUnique 발생



배경


ActiveRecord::RecordNotUnique: Mysql2::Error: Duplicate entry '1-2' for key 'index_seller_id_and_item_id'

같은 오류.

셀러 테이블
id
name

item 테이블
id
name

price 테이블
seller_id
item_id
amount
indexが、index_seller_id_and_item_id の値で貼ってある。

이 상태에서 csv를 통해 bulk import로 작성하는 처리가 있습니다.
게다가 그 CSV의 내용에 복수의 seller_id와 item_id의 중복 세트가 있을 때 발생
seller_id, item_id, amount
1, 1, 100
1, 1, 120

같은 느낌.
new_prices = []
# csvの値を元に既存のレコードかもしくは作成かをする。
price = Price.find_or_initialize_by(seller_id: seller_id, item_id: item_id)
if price.new_record?
  new_prices << price
else
  # 省略
end

# 読み込み処理が終われば、以下でインサート
Price.import new_prices unless new_prices.empty? # <---ここでActiveRecord::RecordNotUniqueが発生

대응 내용



이 경우의 처리는 어떻게 하면 좋을까 고민했지만, seller는 item에 대해 하나의 price 밖에 붙일 수 없기 때문에,
csv에서 뒤의 열에 기술된 처리를 바탕으로 레코드를 작성하도록 수정을 했다.
new_prices = []
# csvの値を元に既存のレコードかもしくは作成かをする。
price = Price.find_or_initialize_by(seller_id: seller_id, item_id: item_id)
if price.new_record?
  new_prices.unshift(price) # uniqは一番最初にマッチしたものを残す為、常にunshiftで先頭に追加していく。
  new_prices.uniq! { |p| [p.item_id, p.seller_id] }
else
  # 省略
end

되돌아 보는 것



최후의 에러에 대해서는 실장할 때에 제대로 csv로 넣어지는 값에 대한 케이스를 테스트로 쓰고 있으면 막았을지도 모르겠지만, 그 이외의 에러에 대해서는 풀 리퀘스트의 리뷰로 막았다고 하는 이미지 별로 없다.
아무래도 에러는 나오지만, 나오면 곧바로 고치는, 라고 하는 스탠스는 잘못되어 있지 않다고 믿고 싶다.
마침내, 롤바, 항상 감사합니다. 앞으로도 오류 알림을 부탁드립니다

그럼 여러분, 좋은 해를. 🐈🌟

좋은 웹페이지 즐겨찾기