Rails 作业随机丢失对模块的引用

Rails Job loses reference to module randomly

编辑:当我手动分叉进程时会发生同样的事情...
Rails 作业调用我的模块 RedisService.
时出现一些奇怪的行为 我已经将 lib/modules 添加到我的 autoload_paths 但是调用 RedisServiceTextService 模块失去了对它的引用,有时是立即,有时是 3 或 4 个工作调用.. .
我什至要求我的 TextService 中的模块无济于事,甚至添加了一些 puts 来检查是否始终显示模块已定义并响应我正在调用的方法...!
有些东西逃脱了我... Here's a gist to the backtrace
回购:https://gitlab.com/thomasbromehead/snmp-simulator-ruby-managerruby --version: 2.6.5 rails version: 6.1.3.1

我的“服务”对象: 调用RedisService的模块

require_relative 'redis_service'

module TextService
  def self.write_to_file(dataObject, redis, path: "./")
    begin
      file_with_path = path + dataObject.filename
      # Store all lines prior to the one being modified, File.read closes the file
      f = File.read(file_with_path)
      new_content = f.gsub(dataObject.old_set_value, dataObject.new_set_value)
      # File.open closes the file when passed a block
      File.open(file_with_path, "w") { |file| file.puts new_content }
      puts "Redis is: #{redis}"                                    ======> RedisService
      puts "Redis responds to multi: #{redis.respond_to?(:multi)}" ======> true
      redis.multi do
        redis.zrem("#{dataObject.name}-sorted-set", dataObject.old_set_value)
        redis.hset("#{dataObject.name}-offsets", "#{dataObject.start_index}:#{dataObject.oid}:#{dataObject.end_index}", dataObject.new_set_value)
        redis.zadd("#{dataObject.name}-sorted-set", dataObject.start_index, dataObject.new_set_value)
      end
    rescue EOFError
    end
  end

从 VariateJob 调用的变体 class

require_relative '../../../lib/modules/redis_service'

module Snmp
  class Variation
    include ActiveModel::Model

    attr_reader :oid, :type, :duration, :to, :from, :filename, :redis

    def initialize(oid:nil, duration:nil, type:nil, to:nil, filename: nil, from:nil)
      @to = to
      @from = from
      @oid = oid
      @type = type
      @filename = filename
      @redis = RedisService
    end

    def run(data)
      current_value, new_set_value, start_index, end_index  = prepare_values(JSON.parse(data))
      transferData = Snmp::TransferData.new({
        filename: @filename,
        old_set_value: current_value,
        new_set_value: new_set_value,
        start_index: start_index,
        end_index: end_index,
        name: @name,
        oid: oid
      })
      TextService.write_to_file(transferData, @redis)
    end

变量作业

class VariateJob < ApplicationJob
  queue_as :default
  def perform(dumped_variation, data)
    Marshal.load(dumped_variation).run(Marshal.load(data))
  end
end

变体控制器

class VariationsController < ApplicationController
  before_action :set_file_name, only: :start

  def start
    if params["linear"]
      type = :linear
    elsif params["random"]
      type = :random
    end
    data = redis.hscan_each("#@name-offsets", match: "*:#{params["snmp_variation"]["oid"]}*")
    # data is an Enumerator, transform it to an array and dump to JSON
    variation = Snmp::Variation.new(params_to_keywords(params["snmp_variation"]).merge({type: type}))
    VariateJob.perform_later(Marshal.dump(variation), Marshal.dump(JSON.generate(data.to_a.first)))
  end

Redis服务

require 'redis'

module RedisService
  include GlobalID::Identification

[...]
  def self.multi(&block)
    @redis.multi { block.call() }
  end
[...]
end

您并没有丢失对 RedisService 的引用,而是在您的 RedisService 中丢失了对 Redis 的引用。可能是因为您使用的服务器或工作程序会分叉新进程,并且在分叉后没有初始化新连接。

要解决此问题,我将替换此方法

def self.start(host,port)
  @redis ||= Redis.new(host: host, port: port)
  self
end

def self.redis
  @redis ||= Redis.new(host: ::Snmpapp.redis_config[:host], port: ::Snmpapp.redis_config[:port])
end

然后我会将对 @redis 的所有调用替换为对新方法的 redis 调用。