bestsource

Mysql2:: 오류: 잠금을 시도할 때 교착 상태가 발견되었습니다. 트랜잭션을 다시 시작해 보십시오(Ruby on Rails).

bestsource 2023. 9. 6. 22:11
반응형

Mysql2:: 오류: 잠금을 시도할 때 교착 상태가 발견되었습니다. 트랜잭션을 다시 시작해 보십시오(Ruby on Rails).

Ruby on Rails 애플리케이션에 문제가 있습니다.그래서, 다른 토끼를 듣고 있는 노동자들이 있습니다.MQ 주제.각 작업자는 DB(mariaDB) 테이블을 약간 변경하고 공통 개체 '장치'의 업데이트 종료 'last_connection' 필드에서 문제가 발생합니다.

이 직원은 한 명입니다.

  include Sneakers::Worker
  # This worker will connect to "queue" queue
  # env is set to nil since by default the actuall queue name would be
  # "queue_development"
  from_queue "sensor_log"

  # work method receives message payload in raw format
  def work(raw_message)
    logger.info ("sensor_log " + raw_message)
    msg = JSON.parse(raw_message)

   # msg = {"deviceId" => 102,"timestamp" => 1487318555,"sensor" => 5, "values" => [1,2,3,4,5,6,7,8], "isNewSensor" => false, "logDelayed" => false}
    begin
      @device = Device.find(msg["deviceId"])

   ActiveRecord::Base.transaction do
        # Initialize
        timestamp = Time.at(msg["timestamp"])

        MiddlewareLog.create(
          device_id: msg["deviceId"],
          message: JSON.pretty_generate(msg),
          queue: MiddlewareLog.queues[:sensor_log]
        )

        if(msg["ext_brd_type"] == 6)

          logger.info ("Logging external sensors lm2, lm4, lm4")
          # Logging external sensors lm2, lm4, lm4
          Sensors::SENSORS_EXT.map do |code|
            SensorLog.create(
                device_id: msg["deviceId"],
                sensor: code,
                state: msg[code],
                value: msg[code],
                is_delayed: msg["logDelayed"],
                created_at: timestamp
            )
          end

        else

          logger.info ("Logging native sensors")
          # Logging native
          device_sensors = @device.new_version? ? Sensors::SENSORS_CODES_NEW : Sensors::SENSORS_CODES
          @sensors = device_sensors.reject{|code, sensor| code & msg["sensor"] == 0}
          @sensors.map do |code, sensor|
            SensorLog.create(
              device_id: msg["deviceId"],
              sensor: sensor[:name],
              state: sensor[:state],
              value: msg["values"][sensor[:bit_position]],
              is_delayed: msg["logDelayed"],
              created_at: timestamp
            )
          end
          Rollbar.warning("Unknown device sensor", :message => msg, :sensor => msg["sensor"]) if @sensors.empty?

          @device.update_sensors_state(msg["values"]) if @sensors.any?

        end

        # Avoid updated_at deadlock
        @device.save!(touch: false)
      end


      # Touch updated_at and last_connection_at
      @device.touch(:last_connection_at)
      ack! # we need to let queue know that message was received
    rescue => exception
      logger.error ("sensors_log exception:")
      logger.error exception
      Rollbar.error(exception, :message => msg)
      requeue!
    end
  end
end

두 번째는 다음과 같습니다.

class SystemLogsWorker
  include Sneakers::Worker
  # This worker will connect to "queue" queue
  # env is set to nil since by default the actuall queue name would be
  # "queue_development"
  from_queue "system_log"

  # @logger = Logger.new(STDOUT)
  # @logger.level = Logger::INFO

  # work method receives message payload in raw format
  def work(raw_message)
    # @logger.info raw_message
    logger.info ("system_log " + raw_message)
    msg = JSON.parse(raw_message)

    # msg = {"deviceId":102,"timestamp":1487318555,"system":2069,"logDelayed":false,"fault_code":1}
    begin
      @device = Device.find(msg["deviceId"])

      ActiveRecord::Base.transaction do
        # Initialize
        timestamp = Time.at(msg["timestamp"])

        MiddlewareLog.create(
            device_id: msg["deviceId"],
            message: JSON.pretty_generate(msg),
            queue: MiddlewareLog.queues[:system_log]
        )

        @system = Systems::EVENTS_CODES[msg["system"]]

        # @logger.warn("Unknown device system", :message => msg, :system => msg[:system]) unless @system
        # logger.warn("Unknown device system", :message => msg, :system => msg["system"]) unless @system
        # Rollbar.warning("Unknown device system", :message => msg, :system => msg["system"]) unless @system
        logger.warn("Unknown device system. Message:" + raw_message) unless @system
        Rollbar.warning("Unknown device system. Message:" + raw_message) unless @system
        # Loggin
        system_log = SystemLog.create(
            device_id: msg["deviceId"],
            system: @system[:name],
            state: @system[:state],
            is_delayed: msg["logDelayed"],
            fault_code: msg["fault_code"],
            created_at: timestamp
        ) if @system

        @device.update_systems_state(system_log) if @system

        # Avoid updated_at deadlock
        @device.save!(touch: false)
      end

      # Touch updated_at and last_connection_at
      @device.touch(:last_connection_at)
      ack! # we need to let queue know that message was received
    rescue => exception
      logger.error ("system_log exception:")
      logger.error exception
      Rollbar.error(exception, :message => msg)
      requeue!
    end
  end
end

런타임에 다음 메시지가 나타납니다.

2020-06-18T11:09:08Z p-13299 t-gmvtsrzac ERROR : sensors_log 예외 : 2020-06-18T11:09:08Z p-13299 t-gmvtsrzac ERROR : Mysql2 ::오류:잠금을 시도할 때 교착 상태가 발견되었습니다. 트랜잭션을 다시 시작해 보십시오.devices세트devices.updated_at= '2020-06-18 11:09:08',devices.last_connection_at= '2020-06-18 11:09:08' WHEREdevices.id= 3024

2020-06-18T11:09:08Z p-13299 t-gmvtsq74w 오류: system_log 예외: 2020-06-18T11:09:08Z p-13299 t-gmvtsq74w 오류: Mysql2::오류:잠금을 시도할 때 교착 상태가 발견되었습니다. 트랜잭션을 다시 시작해 보십시오.devices세트devices.updated_at= '2020-06-18 11:09:08',devices.last_connection_at= '2020-06-18 11:09:08' WHEREdevices.id= 3024

제 생각에 문제는.@device.touch(:last_connection_at), 한 번에 두 작업자 모두 테이블 행 하나를 업데이트하려고 하기 때문입니다.저는 루비를 잘 못해서 어떤 도움이라도 주시면 감사하겠습니다.

데이터베이스 데이터를 업데이트하기 전에 트랜잭션 내에서 잠금을 사용해 본 적이 있습니까?

@device.lock!
@device.save!(touch: false)
@device.touch(:last_connection_at)

with_lock:을 사용하여 잠금과 트랜잭션을 동시에 시작할 수도 있습니다.

@device = Device.find(msg["deviceId"])

@device.with_lock do
  # your block here
end

https://api.rubyonrails.org/classes/ActiveRecord/Locking/Pessimistic.html 설명된 바와 같이

언급URL : https://stackoverflow.com/questions/62449458/mysql2error-deadlock-found-when-trying-to-get-lock-try-restarting-transactio

반응형