Skip to content

Commit 9db6ae4

Browse files
authored
ElixirQueue.WorkerPool readme
1 parent 8c09b0e commit 9db6ae4

File tree

1 file changed

+2
-0
lines changed

1 file changed

+2
-0
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ Os filhos, de cima para baixo, representam as seguintes estruturas: `ElixirQueue
2020
Eis aqui o processo que controla a inserção de elementos na fila. Um _event loop_ por padrão é uma função que executa numa iteração/recursão _pseudo infinita_, uma vez que não existe a intenção de se quebrar o _loop_. A cada ciclo o _loop_ busca _jobs_ adicionados na fila - ou seja, de certa forma o `ElixirQueue.EventLoop` "escuta" as alterações que ocorreram na fila e reage a partir desses eventos - e os direciona ao `ElixirQueue.WorkerPool` para serem executados. Este módulo assume o _behaviour_ de `Task` e sua única função (`event_loop/0`) não retorna nenhum valor tendo em vista que é um _loop_ eterno: ela busca da fila algum elemento e pode receber ou uma tupla `{:ok, job}` com a a tarefa a ser realizada ou uma tupla `{:error, :empty}` para caso a fila esteja vazia; no primeiro caso ele envia para o `ElixirQueue.WorkerPool` a tarefa e executa `event_loop/0` novamente; no segundo caso ele apenas executa a própria função recursivamente, continuando o loop até encontrar algum evento relevante (inserção de elemento na fila).
2121
### ElixirQueue.Queue
2222
O módulo `ElixirQueue.Queue` guarda o coração do sistema. Aqui os _jobs_ são enfileirados para serem consumidos mais tarde pelos _workers_. É um `GenServer` sob a supervisão da `ElixirQueue.Application`, que guarda uma tupla como estado e nessa tupla estão guardados os jobs - para entender o porquê eu preferi por uma tupla ao invés de uma lista encadeada (`List`), mais abaixo em **Análise de Desempenho** está explicado. A `Queue` é uma estrutura bem simples, com funções triviais que basicamente limpam, buscam o primeiro elemento da fila para ser executado e insere um elemento ao fim da fila, de forma a ser executado mais tarde, conforme inserção.
23+
### ElixirQueue.WorkerPool
24+
Aqui está o módulo capaz de se comunicar tanto com a fila quanto com os _workers_. Quando a _Application_ é iniciada e os processos supervisionados, um dos eventos que ocorre é justamente a inciação dos _workers_ sob a supervisão do `ElixirQueue.WorkerSupervisor`, um `DynamicSupervisor`, e os seus respectivos _PIDs_ são adicionados ao estado do `ElixirQueue.WorkerPool`. Quando o `WorkerPool` recebe o pedido para executar um _job_ ele procura por algum de seus _workers PIDs_ que esteja no estado ocioso, ou seja, sem nenhum job sendo executado no momento. Então, para cada _job_ recebido pelo `WorkerPool` através de seu `perform/1`, este vincula o _job_ a um _worker PID_, que passa para o estado de ocupado. Quando o worker termina a execução, limpa seu estado e então fica ocioso, esperando por outro _job_. No caso, isso que aqui chamamos de _worker_ nada mais é do que um `Agent` que guarda em seu estado qual job está sendo executado vinculado àquele PID; ele serve de lastro limitante uma vez que o `WorkerPool` incia uma nova `Task` para cada _job_. Imagine o cenário onde não tivessemos _workers_ para limitar a quantidade de jobs sendo executados concorrentemente: o nosso `EventLoop` inciaria `Task`s a bel prazer, podendo causar grande problemas como estouro de memória caso a `Queue` recebesse uma grande carga de _jobs_ de uma só vez.
2325

2426
## Análise de comportamento assintótico
2527

0 commit comments

Comments
 (0)