ruby on rails - sleep_delay - ¿Cómo probar los reintentos y los fallos en el reintento de reintento y en Rails 4?
rails job work (2)
Por lo tanto, la falla específica por la que desea probar los reintentos proviene de este enlace que implementó.
def lock_failed(*)
raise QueueError::LockFailed
end
Necesitamos desencadenar esto. Here es donde se usa en el plugin. Ya que estás usando un tiempo de espera de bloqueo, parece que queremos .acquire_lock_algorithm!
. Esto es peligroso ya que este método es parte de la API interna del complemento. Téngalo en cuenta cuando actualice el complemento.
it ''retries it'' do
stub_request(:any, /.*api.bigcartel.*/).to_return(body: ''{}'', status: 200)
allow(QueueHook).to receive(:acquire_lock_algorithm!).and_return(false, true)
@order_shipped_json[''order''][''originator_id''] = @provider_order
post "/hook/shops/#{@shop.id}", @order_shipped_json.to_json, format: :json
ResqueSpec.perform_all(queue_name)
end
Esta especificación ahora debería estar fallando con Failure/Error: raise QueueError::LockFailed
. Como eso se espera podemos establecer una expectativa.
it ''retries it'' do
stub_request(:any, /.*api.bigcartel.*/).to_return(body: ''{}'', status: 200)
allow(QueueHook).to receive(:acquire_lock_algorithm!).and_return(false, true)
@order_shipped_json[''order''][''originator_id''] = @provider_order
post "/hook/shops/#{@shop.id}", @order_shipped_json.to_json, format: :json
expect {
ResqueSpec.perform_all(queue_name)
}.to raise_error(QueueError::LockFailed)
end
La especificación debería pasar ahora a menos que haya establecido ResqueSpec.inline = true
. Si lo has hecho, configúralo en falso para esta especificación. Será más fácil de seguir.
Si el reintento de reintento está funcionando, la falla del trabajo debería haber dado como resultado que el trabajo se haya vuelto a poner en cola en ResqueSpec. Podemos agregar una expectativa para eso. expect(ResqueSpec.queues[queue_name]).to be_present
. No podemos volver a ejecutar los trabajos. ¡Nos burlamos del segundo valor de retorno de acquire_lock_algorithm!
para ser verdad por lo que el trabajo debe tener éxito esta vez.
Como queremos probar los contadores, vamos a agregar lectores para ellos.
module QueueLogger
attr_reader :all_attempts, :num_attempts
end
Y luego terminar la especificación ...
it ''retries it'' do
stub_request(:any, /.*api.bigcartel.*/).to_return(body: ''{}'', status: 200)
allow(QueueHook).to receive(:acquire_lock_algorithm!).and_return(false, true)
@order_shipped_json[''order''][''originator_id''] = @provider_order
post "/hook/shops/#{@shop.id}", @order_shipped_json.to_json, format: :json
# Failing
expect {
ResqueSpec.perform_all(queue_name)
}.to raise_error(QueueError::LockFailed)
expect(ResqueSpec.queues[queue_name]).to be_present
# Retrying
ResqueSpec.perform_all(queue_name)
expect(QueueHook.num_attempts).to eq(2)
... # Whatever else you want to test.
end
Si desea probar el registro específicamente, los apaga y establece expectativas con respecto a cómo se les llama. Eso debería hacerlo, tengo una versión simplificada que se ejecuta en mi propia máquina. Si no, podríamos tener que entrar en los detalles de su prueba y Resque Configs.
Estoy tratando de escribir una especificación que pruebe la funcionalidad de reintento del reintento de reintento y parece que no puedo hacer que las pruebas alcancen el enlace .pry correctamente. ¿Hay alguna forma de probar esta funcionalidad utilizando rspec 3 para que pueda verificar que funcionan como es debido?
Esta es una especificación de solicitud y estoy tratando de simular una solicitud en vivo a través de dispositivos, pero no importa lo que intente, parece que no puedo volver a intentar el trabajo.
gem ''resque'', require: ''resque/server''
gem ''resque-web'', require: ''resque_web''
gem ''resque-scheduler''
gem ''resque-retry''
gem ''resque-lock-timeout''
Estoy usando resque_rspec y probando esta estrategia de prueba .
Especificaciones parciales
it ''retries it'' do
stub_request(:any, /.*api.bigcartel.*/).to_return(body: ''{}'', status: 200)
@order_shipped_json[''order''][''originator_id''] = @provider_order
post "/hook/shops/#{@shop.id}", @order_shipped_json.to_json, format: :json
ResqueSpec.perform_all(queue_name)
???
end
Trabajo en cola
class QueueHook
extend Resque::Plugins::LockTimeout
extend Resque::Plugins::Retry
extend QueueLock
extend QueueLogger
@queue = AppSettings.queues[:hook_queue_name].to_sym
@lock_timeout = 600
@retry_exceptions = [QueueError::LockFailed]
@retry_limit = 600
@retry_delay = 1
class << self
def perform(web_hook_payload_id, _whiplash_customer_id)
ActiveRecord::Base.clear_active_connections!
@web_hook_payload = WebHookPayload.find(web_hook_payload_id)
klass_constructor
@hook.process_event
end
def identifier(_web_hook_payload_id, whiplash_customer_id)
"lock:integration_hook:#{whiplash_customer_id}"
end
def after_perform_delete_webhook(_web_hook_payload_id, _whiplash_customer_id)
@web_hook_payload.destroy
end
private
...
end
end
Módulos de trabajo de cola
module QueueLogger
def before_perform_log_job(*args)
Rails.logger.info "[Resque][#{self}] running with #{args.inspect}..."
end
def on_failure_log_job(*args)
message = "[Resque][#{self}] failed with #{args.inspect}..."
run_counters
Rails.logger.info message_builder(message)
end
private
def run_counters
@num_attempts += retry_attempt
@all_attempts += retry_limit
end
def message_builder(message)
return message unless @num_attempts
return message += " Retrying (attempt ##{@num_attempts + 1})" if @num_attempts < @all_attempts
message += '' Giving up.''
message
end
end
module QueueLock
def loner_enqueue_failed(*args)
Rails.logger.info "[Resque][#{self}] is already enqueued: #{args.inspect}..."
end
def lock_failed(*)
raise QueueError::LockFailed
end
end
Unas pocas notas
1) Como lo mencionaron otros, es probable que desee separar las devoluciones de llamada de resque
de su funcionalidad. Es decir, compruebe que los retries
están activando, pero también pruebe por separado que funcionan como se espera. Es posible que desee separarlos en dos pruebas separadas.
2) Para verificar que están disparando, creo que está buscando dobles de clase en RSpec 3.
Deberá incluir el doble y luego generar una excepción ( docs ). Esto le permitirá ver si se están llamando sus retries
y cuántas veces se han llamado ( docs ).
Así por ejemplo,
it "retries on exception n number of times" do
queue_hook = class_double("QueueHook")
expect(queue_hook).to have_received(:on_failure_log_job).exactly(n).times
allow(queue_hook).to receive(:perform).and_raise(ExceptionClass, "Exception message")
queue_hook.perform(payload_id, customer_id)
end
Hay un poco en juego, por lo que no puedo implementar localmente, pero espero que esto pueda ayudarlo a avanzar en la dirección correcta.