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