Fila assíncrona opcional
Acbr\Async\AsyncEmitter devolve um Future logo após agendar e iniciar o primeiro trabalho. A operação executa em outro processo PHP, que abre seu próprio worker. A fila é FIFO, com uma operação ativa por instância; não é durável e não recupera jobs depois de reinício.
Requisitos e ambiente
Use PHP 8.2+, Linux x64/glibc, SAPI CLI, ext-pcntl, ext-posix, stream_socket_pair, proc_open e funções de processo habilitadas. Sem backend, a biblioteca lança ASYNC_INDISPONIVEL, sem fallback síncrono disfarçado.
Não use essa fila em FPM, Apache/mod_php, runtime multithread ou depois de abrir recursos que não podem ser herdados com segurança por fork(), como conexões de banco e clientes de rede. Prefira um CLI dedicado. Um job de framework pode usar o Emitter síncrono sem essas extensões opcionais.
O processo deve manter a política padrão de SIGCHLD; um handler próprio ou SIG_IGN é rejeitado por ASYNC_SIGNAL_INCOMPATIVEL. Não recolha os filhos da fila externamente nem use reaper indiscriminado como pcntl_waitpid(-1, ...) durante sua execução. A fila só sinaliza filhos/grupos privados cuja propriedade consegue confirmar.
Uso local completo
Veja async-offline.php, que gera XML e agenda a validação local. A validação de XML não assinado pode retornar falha de schema esperada.
use Acbr\Async\AsyncEmitter;
$async = new AsyncEmitter($emissor, capacity: 8, timeoutMs: 30000);
try {
$primeiro = $async->gerarXml($documento);
// O worker já pode executar enquanto o pai faz trabalho PHP independente.
$resultado = $primeiro->await();
echo json_encode($resultado, JSON_THROW_ON_ERROR), PHP_EOL;
} finally {
$async->fechar();
}Os nove métodos têm os mesmos dados fiscais da API síncrona, mas retornam Future e fornecem o callback de cancelamento internamente. gerarXml transforma arrays em Document imutável ao agendar; argumentos dos demais métodos também são destacados para não mudar quando a aplicação altera referências depois. recuperarXml(string $signedXml): Future segue os limites da recuperação; com motor real, faz consulta de rede.
Capacidade, progresso e prazos
new AsyncEmitter(Emitter $emitter, int $capacity = 16, int $timeoutMs = 120000, int $maxBytes = 8388608) cria a fachada. capacity aceita 1 a 1001 e inclui ativo + pendentes. Com 8, há no máximo um ativo e sete em espera. Um novo item além do limite lança FILA_CHEIA sem executá-lo.
Não existe loop de eventos oculto no pai. Future::await(), tick() e drain() processam respostas e iniciam os próximos itens. Sem essas chamadas, o trabalho já iniciado continua, mas o próximo permanece aguardando. tick(0) não espera dados; ainda pode gastar tempo limitado confirmando limpeza e iniciando outro processo. state(), isComplete() e result() também fazem uma passagem de progresso.
O timeout da fila aceita 1 a 120000 ms e começa quando o item executa; espera na fila não consome esse prazo. O timeout do Emitter também se aplica. O agendamento tem handshake local limitado; verificação, limpeza, escalonamento e contrapressão IPC podem aumentar o tempo total observado. maxBytes limita o envelope IPC, padrão 8 MiB, além do limite do transporte. Dimensione a memória para vários itens; a fila não persiste em disco.
drain() aguarda todos os futuros, mas não lança os erros fiscais individuais. Leia cada futuro. await() devolve seu FiscalResult ou lança seu erro. result() não espera: lança RESULTADO_PENDENTE se ainda não terminou.
Future e cancelamento
| Método | Comportamento |
|---|---|
state() | pending, running, fulfilled ou rejected |
isComplete() | Informa se terminou, depois de progresso curto |
cancel() | Solicita interrupção; false quando já terminado |
await() | Aguarda o próprio resultado enquanto progride a fila |
result() | Acesso somente ao resultado concluído |
Cancelar pendente impede execução e gera OPERACAO_CANCELADA conhecida. Cancelar ativo não desfaz efeito remoto e pode deixar resultado incerto. Future::cancel() é cancelamento do trabalho local; AsyncEmitter::cancelar($dados) é um evento fiscal distinto.
fechar() rejeita pendentes e tenta encerrar o ativo com prazo de limpeza limitado; também fecha o emissor. A tentativa pode lançar se a limpeza não for confirmada, caso em que a fila fica permanentemente fechada. Guarde a fachada até os futuros terminarem e feche em finally; o destrutor é apenas uma tentativa de proteção.
O runtime Linux fixado usa proteção de morte do pai para seu worker, mas callbacks próprios não ganham essa garantia automaticamente. Descendentes arbitrários, bloqueio no kernel e zumbis órfãos podem impedir prova de limpeza. Não crie trabalho destacado ou processos fora da supervisão.
OperationQueue de baixo nível
use Acbr\Async\OperationQueue;
use Acbr\FiscalResult;
$fila = new OperationQueue(capacity: 4, timeoutMs: 30000);
try {
$futuro = $fila->submit(
static fn(callable $cancelled): FiscalResult => $emissor->validar($xml, $cancelled),
mayHaveFiscalEffect: false,
);
$resultado = $futuro->await();
} finally {
$fila->close();
}mayHaveFiscalEffect é true por padrão. Só use false para operação local/consulta sem efeito fiscal. Callbacks devem ser confiáveis, retornar FiscalResult, repassar o probe e não depender de conexões herdadas. Capturas mutáveis dessa API são copiadas ao iniciar via fork(), não necessariamente ao agendar; prefira AsyncEmitter para snapshot já validado.
Não há serialização global entre duas filas, processos ou chamadas síncronas. Coordenação fiscal e exclusão por intenção pertencem à aplicação consumidora. XML, A1 e CSC continuam sensíveis em memória; o IPC preserva recuperação explícita quando possível, sem inseri-la em JSON/debug.