Gerenciamento de recursos
Queuety divide o controle de recursos em quatro camadas principais, além do dimensionamento opcional de pools.
A primeira camada descreve o custo de uma unidade de trabalho. A segunda limita quanta pressão compartilhada uma fila ou grupo de provedores pode suportar de uma só vez. A terceira define quanto uma única execução de workflow pode consumir. A quarta decide se um worker deve iniciar o próximo job reivindicado imediatamente ou adiá-lo até que o processo e o contêiner atuais ainda tenham margem suficiente.
Essas camadas trabalham em conjunto. Um handler pode declarar que pertence a um pool compartilhado de alto custo; uma fila pode reservar uma quantidade limitada de trabalho ponderado para um provedor; um workflow pode limitar quanto desse trabalho está disposto a criar; e o worker ainda pode se recusar a iniciar mais trabalho quando o processo ou contêiner atual já está perto demais dos próprios limites.
Descreva o custo de uma unidade de trabalho
Jobs, etapas de workflow e ações de entrada de estado podem publicar as mesmas três indicações de recursos:
concurrency_groupconcurrency_limitcost_units
concurrency_group e concurrency_limit descrevem a pressão compartilhada sobre um sistema downstream. Se vários handlers acessam o mesmo provedor, conta API ou tenant, eles podem usar o mesmo grupo para que os workers não iniciem muitos jobs ao mesmo tempo.
cost_units descreve o peso relativo. Uma atualização de cache e uma chamada grande a um provedor podem ser ambas “um job”, mas não devem contribuir igualmente quando um orçamento de workflow ou uma regra de admissão de worker decide se ainda é seguro iniciar mais trabalho.
final class CallProviderStep implements \Queuety\Step
{
public function handle( array $state ): array
{
// ...
}
public function config(): array
{
return [
'concurrency_group' => 'providers',
'concurrency_limit' => 3,
'cost_units' => 5,
];
}
}
A mesma ideia se aplica a jobs que podem ser despachados por meio de propriedades da classe e a despachos individuais por meio de PendingJob::concurrency_group() e PendingJob::cost_units().
Defina orçamentos para filas e grupos de provedores compartilhados
A pressão compartilhada nem sempre se resume a uma simples contagem de concorrência. Às vezes, o aspecto custoso é o peso combinado do que já está em execução.
Queuety oferece suporte a isso por meio de orçamentos ponderados para filas e grupos. Os orçamentos de fila são associados ao nome da fila. Os orçamentos de grupo são associados a concurrency_group, permitindo que handlers sem relação entre si participem do mesmo limite compartilhado.
define( 'QUEUETY_RESOURCE_QUEUE_COST_BUDGETS', [
'providers' => 20,
'exports' => 8,
] );
define( 'QUEUETY_RESOURCE_GROUP_COST_BUDGETS', [
'openai' => 12,
'tenant:acme' => 6,
] );
Quando um worker reivindica um job, ele verifica as linhas ativas de processing que já pertencem àquela fila ou grupo. Se o custo atualmente em execução somado ao cost_units do job reivindicado exceder o orçamento configurado, o worker libera o job e tenta novamente mais tarde.
Isso oferece um controle diferente de concurrency_limit. Um provedor pode permitir três solicitações simultâneas, mas ainda assim reservar menos unidades de custo totais para solicitações maiores do que para as menores.
Mantenha um workflow dentro de um limite
Os orçamentos de workflow são úteis quando o problema não é um único job pesado, mas uma execução que continua descobrindo mais trabalho do que deveria.
Isso é comum em sistemas agênticos. Um planejador pode revisitar o mesmo ramo custoso, dividir cada um em subtarefas demais ou continuar iniciando workflows filhos enquanto permanece tecnicamente dentro de um modelo normal de novas tentativas.
Queuety oferece limites no nível do workflow para isso:
Queuety::workflow( 'research_run' )
->max_transitions( 20 )
->max_for_each_items( 12 )
->max_state_bytes( 32768 )
->max_cost_units( 40 )
->max_started_workflows( 8 )
->then( PlanResearchStep::class )
->for_each( 'tasks', ExecuteResearchTask::class, 'results' )
->dispatch();
max_cost_units() impede que a execução consuma mais trabalho ponderado do que o previsto. max_started_workflows() impede que um workflow pai se transforme em uma árvore ilimitada de execuções filhas de nível superior. As outras proteções continuam sendo importantes, pois nem todo workflow descontrolado é custoso da mesma maneira.
O status do workflow expõe os limites configurados e o uso atual por meio do payload público budget, permitindo inspecionar a execução enquanto esses limites estiverem ativos.
Permita que os workers adiem trabalho quando o processo já estiver sobrecarregado
Mesmo quando os metadados e os orçamentos do workflow estão bem configurados, a decisão final ainda cabe ao processo de worker que está prestes a executar o job.
É aí que entra a admissão com reconhecimento de recursos. Antes de iniciar um job reivindicado, Queuety pode verificar:
- o grupo de concorrência compartilhado do job
- os orçamentos ponderados da fila e do grupo de provedores
- o histórico recente de duração e pico de memória do handler
- a memória disponível no worker atual
- a memória disponível no contêiner ou host atual
- o tempo restante para execuções no estilo de execução única
Se o worker já estiver perto demais do limite configurado, Queuety libera o job em vez de iniciar um trabalho que provavelmente não será concluído corretamente.
Essa abordagem é deliberadamente conservadora. Não é um agendador completo de cluster. É uma camada de segurança que ajuda um worker ocupado a evitar sobrecarregar o processo em que está sendo executado e, quando há telemetria de memória disponível, o contêiner ou host ao redor dele.
A verificação do contêiner ou host é opcional. Quando QUEUETY_RESOURCE_SYSTEM_MEMORY_AWARENESS está habilitado, Queuety tenta ler primeiro os dados de memória do cgroup e recorre a /proc/meminfo em hosts Linux. Se não houver um retrato confiável do sistema disponível, o worker continua usando as verificações locais do processo.
Dimensione pools de workers sem ignorar a capacidade
Pools fixos de workers são fáceis de entender, mas também obrigam você a escolher um único número para períodos tranquilos e picos.
Pools adaptáveis permitem definir um mínimo e um máximo:
wp queuety work --queue=providers --min-workers=2 --max-workers=6
O processo pai mantém pelo menos o número mínimo de processos filhos ativos, cresce em direção ao máximo quando aumenta o backlog de jobs disponíveis para reivindicação e reduz o tamanho do pool após a fila ficar sem atividade durante o período de tolerância de inatividade configurado.
O aumento ainda respeita a capacidade disponível. Se o reconhecimento da memória do sistema estiver habilitado e o processo pai não detectar memória disponível suficiente para mais um worker completo, ele mantém o pool no tamanho atual em vez de iniciar mais processos filhos.
Um exemplo realista de combinação das camadas
Imagine um workflow de pesquisa que planeja chamadas a provedores, inicia workflows especializados e, em seguida, sintetiza o resultado.
A etapa voltada ao provedor pode publicar cost_units e um concurrency_group compartilhado para que vários workers não sobrecarreguem o mesmo provedor de modelo. A fila pode reservar um orçamento ponderado para esse tráfego do provedor. O workflow pai pode limitar max_cost_units() e max_started_workflows() para que um planejador não expanda a execução indefinidamente. Depois, o worker ainda pode adiar uma chamada recém-reivindicada ao provedor se os dados recentes de pico de memória indicarem que o processo ou contêiner já está perto demais do limite.
Isso oferece quatro controles distintos:
- Descrever o peso do trabalho
- Reservar capacidade compartilhada da fila ou do provedor
- Limitar o que uma execução pode criar
- Impedir que um worker sobrecarregado inicie mais trabalho do que deveria
Onde encontrar as APIs detalhadas
Esta página é uma visão geral conceitual.
Para conhecer os controles específicos:
- Workers aborda o comportamento de admissão e as constantes de execução
- CLI aborda comandos para pools fixos e adaptáveis de workers
- Proteções do workflow aborda os orçamentos de workflow
- Jobs aborda metadados de jobs e handlers
- Máquinas de estado aborda metadados de recursos de ações de estado
- API lista os métodos exatos e os formatos de retorno