work sleep_delay rails perform method job delayed_job delayed daemonize ruby-on-rails ruby rspec resque resque-retry

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.