O webhook do Postiz que eu não consegui construir, e o polling em vez dele
Meu blog manager agenda posts sociais através do Postiz, um agendador self-hosted. Agendar é a metade fácil. A metade difícil é descobrir, depois, onde o post realmente foi parar. O Postiz publica de forma assíncrona, então a chamada de “agendar” retorna antes de qualquer coisa estar no ar e sem link nenhum para o post publicado. O plano no papel era simples: receber o webhook de publicação do Postiz e registrar a URL. Eu nunca cheguei a escrever esse receptor, e o motivo dele ter morrido é mais interessante do que o código que o substituiu.
Lendo antes de construir
O Postiz é open source, então em vez de adivinhar o payload do webhook eu fixei minha leitura na versão exata que minha máquina roda (v2.21.8) e rastreei o caminho de publicação. Duas descobertas, qualquer uma delas fatal.
Ele não aceita minha URL. A configuração do webhook valida o destino com uma função chamada IsSafeWebhookUrl. Ela faz uma consulta DNS de verdade e rejeita qualquer coisa que resolva para um endereço privado, 10.x, 192.168.x, e por aí vai. Meu blog manager vive num domínio do homelab que resolve para um endereço privado 192.168.x.x. O Postiz recusa registrá-lo. Não existe um endpoint público para apontar, então eu nem consigo criar o webhook.
E o payload está vazio de qualquer forma. Mesmo deixando de lado o problema da URL, o webhook da v2.21.8 não é autenticado (sem secret, sem assinatura, eu não teria como saber se um POST é realmente do Postiz), dispara só em caso de sucesso (então falhas ficam invisíveis) e, por causa de um id incompatível no código-fonte, faz POST de um array vazio. A função que monta o corpo busca o post pelo id errado, não encontra nada, e envia []. Rastreei linha por linha e ainda assim meio que esperava estar errado, mas o caminho é inequívoco.
Então a feature, como especificada, era impossível de construir. Isso é um resultado útil: um spike que termina em “não construa isso” me poupou de montar um ingress público e um receptor só para captar pings vazios e não verificáveis.
Polling, a resposta chata que funciona
A coisa sobre um sistema assíncrono com um webhook ruim é que, na maioria das vezes, você pode simplesmente perguntar a ele. O Postiz tem um endpoint de leitura, GET /posts sobre um intervalo de datas, e quando eu chamei com minha API key, todo campo que o webhook deveria entregar estava ali: por canal, o estado (QUEUE / PUBLISHED / ERROR), a URL publicada, o nome do provider. Autenticado, completo, e ainda me conta sobre falhas que o webhook nunca contaria.
Então eu faço polling. Quando um post é agendado, eu capturo o id de post por canal que o Postiz devolve, e um background job checa o calendário um minuto depois, casa meus ids contra ele, e registra onde cada canal foi parar, mudando o post para “posted” assim que todo canal está no ar, recuando e tentando de novo enquanto algum ainda está na fila. Menos elegante que um push, mas é o tipo de menos elegante que realmente funciona.
A pegadinha: posts de antes de eu capturar ids
Lancei a captura de id e testei, e um post que eu tinha publicado mais cedo naquele dia ainda aparecia como “scheduled.” Claro que sim, ele saiu antes de o código que captura o id de correlação existir, então o poller não tinha nada para casar. Em vez de adivinhar, conferi o que o calendário realmente retorna e achei a URL do post bem ali no conteúdo da linha. Então dei ao poller um fallback: se não há id capturado, casar com a linha do Postiz cujo conteúdo contém a URL do post. Posts novos casam por id; os antigos se autocorrigem por URL. Uma passada de reconciliação e o catálogo antigo acendeu com seus links reais.
O que eu levo dessa experiência
Duas coisas. Primeiro, leia o código-fonte daquilo com que você está integrando antes de desenhar sua solução em cima da documentação ou do issue tracker. O webhook “existe” no sentido de que há código, e “não funciona” no sentido de que o código envia um corpo vazio, e só o código-fonte diz qual dos dois é o caso. Segundo, quando uma push API falha com você, confira se o mesmo sistema tem uma pull API. Geralmente tem, e geralmente é a que de fato é mantida.
Leitura relacionada
Add a feature, or move a responsibility?
Adding Postiz social cross-posting looked done until a blunt question exposed a double-post bug, and a full audit of every posting path in the app found two more like it.
Agendamento e compartilhamento de link mais inteligente no meu cross-poster do Postiz
Agendamento para o futuro, blurbs mais ricos com thumbnails, um seletor de qual URL usar, além do bug de timezone no horário de parede e a importação que copiou a coluna errada.
O último publisher nativo: fechando a consolidação do Postiz
A integração nativa do Medium era uma peça de museu. Uma ponte de navegador, um artigo cujo corpo é uma URL, e menos 1.603 linhas.
Você também pode achar útil
AdGuard para iOS
Bloqueio de anúncios e rastreadores em todo o sistema no iOS, sem necessidade de um servidor DNS separado.
Como afiliado da AdGuard, ganho com compras qualificadas.
Saiba maiseSIM Airalo
eSIM de dados local para viagens - sem necessidade de trocar um SIM físico.
Este é meu link de indicação da Airalo. Você recebe um desconto no seu primeiro eSIM e eu ganho crédito da Airalo para o meu.
Saiba maisProton Mail
E-mail criptografado de ponta a ponta, com arquitetura de acesso zero.
Como parceiro da Proton, ganho com compras qualificadas dos serviços de privacidade e segurança da Proton (Pass, Mail, VPN, Drive).
Saiba mais