Normalmente, quando falamos sobre a arquitetura padrão (MVC, RAILS + HEROKU), temos uma longa caminhada de tráfego. Durante toda essa caminhada (Do request até a response) bloqueamos nossa UX de retornar absolutamente qualquer coisa.

O processo padrão do heroku que lida com essas requisições também é bloqueado. Se a aplicação demorar mais de 30 segundos, ele encerra a conexão te retornando um TIMED OUT.

Ele(Heroku) faz isso, pois o que você verdadeiramente paga no Heroku, são os números de processamentos de aplicações (conhecidos como Dynos).

Existem DOIS TIPOS de Dynos:

  • Web Dyno
  • Worker Dyno

Em alto nível, um Dyno é um processo que roda na sua aplicação Rails.
Um Web Dyno, é um subtópico especialmente feito para lidar com tráfego web.

O Heroku coloca todos os Web Dynos atrás de algo que chamamos de “Routing Mash”

Request -> HTTP Reverse Proxy -> HTTP cache -> Routing Mash -> Dyno Grid

No caso, ao invés de demorar 30 segundos, podemos adicionar o request dentro de uma lista e retornar imediatamente pro usuário uma mensagem do tipo “Adicionamos sua requisição na nossa lista.”

Basicamente, é um key value sem precisar modelar os dados com um banco sequencial (Sim, redis.)

Então, no caso, ao invés de chamar o model.rb para gerar o report, colocamos uma mensagem na fila e ele retornará imediatamente ao usuário. Enquanto isso, nossa fila também se comunica com um worker.

Um worker é um objeto em Ruby que está num processo diferente do que está no mesmo deploy do Web Request.

Pelo fato do serviço estar separado da Web, ele não está registrado nas regras de 30 segundos, ou seja, quando o Worker finalizar o processo, podemos tomar alguma decisão com os dados. Como, por exemplo, mandar um email pro usuário ou subir no Bucket.

Normalmente, adicionamos os dados no cache, para que o usuário veja na Web sem precisar recalcular.

Normalmente usamos sempre o Redis com o Sidekiq….

Redis => Banco de Dados.
Sidekiq => Lib para manusear os processos e aplicações Rails.

Ps: O Sidekiq vêm com sua própria UI, que é feita em Sinatra, logo, você precisa importar o Sinatra.

Exemplos:

#routes.rb

require ‘sidekiq/web’
mount Sidekiq::Web => “/sidekiq”

$ mkdir workers
$ cd workers && touch report_worker.rb

#report_worker.rb

class ReportWorker
  include Sidekiq::worker
  sidekiq_options retry:false

  def perform(start_date, end_date)
    puts("#{start_date} até #{end_date}")
  end
end

No caso acima, usamos o retry: false pois por padrão, se o worker falhar, ele tentará executar o processo até dar certo.
Todo Sidekiq Woker tem um método chamado “Perform”. Ele que é chamado quando algo da fila é processado.

Você pode colocar paramêtros na fila ;).

#controller.rb

def report
  ReportWorker.perform_async("01-01-2020", "01-01-2021")
  render text: "Request Comum"
end

E por último, para sabermos pelo menos como funciona a execução do Sidekiq, para rodarmos ele no terminal, usamos:

sidekiq -c 1

Ele roda todos os processos com uma Thresh (padrão), Mas você pode aumentar esse número.
Por padrão, ele sabe que a fila está no Redis, pois, ele lê a porta 6379 (Padrão do Redis)

Tá Diego, mas como posso dar deploy disso na núvem?

Eu te respondo meu caro:

Na sua aplicação Rails, faça o seguinte:

#procfile

reportworker: bundle sidekiq -c 1

Assim, ele irá executar o mesmo comando que fizemos no nosso terminal local.

:) Não sei finalizar um texto, então….

$ systemctl stop medium-text