Saltar para o conteúdo
Tecnologia

Porque construímos o "Wayler": ETL determinístico num mundo obcecado por IA

Construímos o Wayler, um orquestrador de ETL, simples e determinístico, em vez de recorrer aos gigantes da indústria. Um caso de uso de Python procedimental, das fronteiras do Docker e de processos que fazem exatamente o mesmo, sempre.

Construímos o Wayler, um orquestrador de ETL, simples e determinístico, em vez de recorrer aos gigantes da indústria. Um caso de uso de Python procedimental, das fronteiras do Docker e de processos que fazem exatamente o mesmo, sempre.

Índice

Se passarmos cinco minutos nas redes sociais onde se fala sobre tecnologia, ficamos com a ideia de que a única forma de construir software hoje em dia é lançar um conjunto de agentes de IA autónomos. Não nos interpretem mal — na Waymotion não somos anti-IA. Na verdade, usamos ferramentas de IA todos os dias para escrever código, desenhar sistemas e resolver problemas complexos.

Mas recentemente, perante uma tarefa de migrar dados geoespaciais complexos de serviços ArcGIS REST antigos e de APIs internas para uma OGC API normalizada (ver este caso), decidimos ir contra a corrente: construímos o nosso próprio orquestrador de ETL, simples e determinístico (como antigamente).

Chamámos-lhe Wayler (como usámos docker no core, o nome foi a parte fácil). Eis porque o construímos, porque não optámos pelos gigantes da indústria e como apostar em Docker e em Python procedimental nos deu exatamente o controlo e a sustentabilidade de software de que achámos ser suficiente.

O «problema» das ferramentas de dados modernas

Quando tudo o que precisamos de fazer é recolher dados de uma API, transformá-los para uma norma específica (como o INSPIRE) e carregá-los com segurança para uma base de dados relacional, o ecossistema atual apresenta uma dicotomia frustrante, que é crucial ponderar quando, especialmente numa equipa pequena:

  • Os pesos-pesados (Spark, Airflow, Mage.ai): são ferramentas notáveis para data lakes massivos e distribuídos. Mas configurar um cluster ou escrever abstrações complexas de DAG só para paginar um endpoint ArcGIS REST é como usar uma martelo para partir uma noz.
  • Os construtores visuais (n8n, Zapier): excelentes para webhooks simples, mas transformam-se facilmente em esparguete visual assim que é preciso lidar com transformações geoespaciais complexas ou com conversões de coordenadas (EPSG:3763 para EPSG:4326).

Percebemos que não queríamos abstrair o código, porque queríamos o controlo de escrever Python procedimental. Se for preciso um IF baseado numa escala de 1:50k contra 1:200k, queremos vê-lo explicitamente num ficheiro .py.

Quando processos e builds determinísticos são possíveis, na nossa visão são muitíssimo superiores para a sustentabilidade do software a longo prazo. Não temos de nos interrogar sobre porque é que um LLM alucinou um mapeamento de esquema, nem de desemaranhar um grafo de nós gigantesco. Simplesmente funciona (ou não), exatamente da mesma maneira, sempre.

Além disso, não queríamos depender do sistema operativo da máquina anfitriã nem de SaaS de terceiros para o agendamento. Precisávamos de um agendador nosso, a correr exclusivamente na nossa infraestrutura, totalmente isolado e seguro.

O Wayler e os seus Harpoons

Para resolver isto, desenhámos o Wayler — um orquestrador leve e feito à medida, assente em Docker.

Na nossa arquitetura, o Wayler funciona como centro de comando. Não processa dados; apoia-se numa base de dados local para gerir agendamentos, novas tentativas e alertas. Quando chega a hora agendada, lança um Harpoon — um script Python em contentor, de propósito único.

Arquitetura do WaylerO orquestrador Wayler lê os agendamentos da sua própria base de dados e lança contentores Harpoon de propósito único através da API do Docker. Cada Harpoon recolhe de uma fonte, transforma os dados e carrega-os atomicamente para o PostGIS, que o pygeoapi serve como OGC API pública.Docker engineO Wayler — orquestradorspawnspawnspawnatomic loadatomic load

Scheduler

Wayler DB
schedules · logs

Harpoon
ArcGIS REST

Harpoon
APIs internas

Harpoon
Legacy DB

ArcGIS REST

APIs internas

PostGIS

pygeoapi
OGC API pública

Fig. 1 — O Wayler é dono do agendamento e de mais nada. Cada trabalho é um Harpoon — um contentor, uma fonte, um propósito — e a carga para o PostGIS é a única coisa que a API pública chega a ver.

A decisão Docker: uma funcionalidade, não um defeito

Construir um orquestrador assim traz uma ressalva importante: depende 100% do Docker. O Wayler tem de ter acesso ao socket do Docker para criar contentores, monitorizar os respetivos códigos de saída e destruí-los. Mas, para nós, esta dependência foi deliberada, e acreditamos que foi uma decisão altamente vantajosa.

Ao obrigar cada trabalho de ETL a viver num contentor Docker, garantimos que cada script Python vive no seu próprio mundo. Não há «inferno de dependências» em que uma atualização do GeoPandas para um script estrague outro. Também torna o lançamento de novas versões incrivelmente simples — construímos e etiquetamos uma nova imagem do Harpoon, atualizamos o registo na base de dados, e a execução agendada seguinte usa o novo código sem afetar o resto da frota.

Além disso, isto permitiu-nos impor um comportamento estrito ao SDK (internamente chamamos-lhe «Iron»). Cada Harpoon herda de uma classe Python BaseHarpoon. Os programadores implementam apenas um método process(), e o SDK trata automaticamente do registo consistente, das sessões de base de dados, da captura de erros e de uma flag —dry-run obrigatória.

Veja como é simples implementar um Harpoon com o SDK:

from wayler_sdk import BaseHarpoon
from integrations.arcgis import ArcGISClient

class MineralOccurrencesHarpoon(BaseHarpoon):
    def process(self):
        self.logger.info("Starting Voyage: Fetching ArcGIS data...")

        # 1. Fetch data from source
        client = ArcGISClient(url=self.config.SOURCE_URL)
        raw_data = client.fetch_all_features()

        # 2. Procedural, deterministic transformation
        self.logger.info(f"Retrieved {len(raw_data)} records. Transforming...")
        clean_data = self.transform_to_inspire(raw_data)

        # 3. The SDK handles the atomic swap to the DB
        self.logger.info("Loading into PostGIS Staging...")
        self.atomic_load(
            target_table="stg_inspire_ge_minocc",
            data=clean_data
        )
        self.logger.info("Voyage successful!")

if __name__ == "__main__":
    # The run() method handles dry-runs, retries, and DB sessions
    MineralOccurrencesHarpoon().run()

Entrega de dados sem interrupção (a troca atómica)

O principal consumidor destes dados é um serviço pygeoapi público que lê de uma base de dados PostGIS. Se um Harpoon demora 20 minutos a descarregar e processar milhares de elementos geológicos, a API pública não pode servir dados vazios ou parciais durante essa janela.

Como temos controlo total sobre o Python procedimental, o nosso SDK impõe um padrão de troca atómica:

A troca atómicaUm Harpoon recolhe e transforma os dados para uma tabela temporária e, dentro de uma única transação, troca-a pela tabela em produção, para que a API pública nunca leia dados parciais.pygeoapiPostGISSourceHarpoonWayleruma só transaçãolaunchfetch (paginated)GeoJSONtransform · EPSG:4326CREATE temp tableTRUNCATE live tableINSERT from tempCOMMITexit code 0read live tabledados completos
Fig. 2 — Vinte minutos de trabalho ficam numa tabela temporária. Só a troca corre dentro da transação, pelo que quem lê vê o conjunto completo de ontem ou o de hoje — nunca metade de nenhum.

Para onde vamos a partir daqui (um roteiro possível)

O Wayler revelou-se tão estável que já pensamos alargá-lo a outros processos internos de sincronização, para lá dos dados geoespaciais. Ainda assim, qualquer equipa de engenharia honesta sabe que o seu sistema ainda não é perfeito (e nunca será :D). Temos dois pontos maiores no roteiro de dívida técnica:

  • Uma interface própria: neste momento, gerir o Wayler significa correr alguns comandos docker e escrever INSERTs de SQL clínicos na base de dados do orquestrador. Precisamos de construir um painel limpo e bonito para visualizar pipelines, despoletar execuções manuais de Harpoons e acompanhar os registos.
  • Gestão de segredos: a nossa próxima grande evolução arquitetónica é integrar um gestor de segredos dedicado, para que os Harpoons passem a ir buscar as suas credenciais dinamicamente em tempo de execução (o mage.ai, por exemplo, faz isto muito bem).

Conclusão

Numa era em que a indústria tecnológica corre para entregar todos os fluxos de trabalho a um LLM, vale a pena lembrar que a sincronização de dados é muitas vezes um prato que se serve frio e determinístico. Adoramos a IA naquilo em que ela é melhor. Mas para migrar dados? Não me parece que precisemos dela. Abraçámos a sustentabilidade do Python procedimental, as fronteiras estritas do Docker e a fiabilidade de um agendador feito por nós.

Como programador que tenta acompanhar os superpoderes dos LLM, admito que houve uma pequena parte de mim que temeu, ao início, que a «diversão» da IA se perdesse ao escolher a via tradicional e determinística em vez de um enxame de agentes autónomos. Mas a verdade é que os Harpoons continuam a ter de ser desenvolvidos. A arquitetura continua a ter de ser desenhada, as APIs continuam a ter de ser sujeitas a engenharia inversa, e a IA está mesmo ali, nos nossos IDE, a ajudar-nos a escrever esse Python procedimental mais depressa e melhor do que nunca. Ficamos com a fiabilidade do código determinístico, sem perder a alegria do «desenvolvimento moderno».

O que me deixa a pensar: por vezes, a coisa mais inovadora que se pode fazer é escrever código que faz exatamente aquilo que lhe mandamos fazer, mesmo que seja um bug.

Voltar ao blog

Artigos relacionados

Ver todos os artigos »
A cibersegurança faz mover montanhas

A cibersegurança faz mover montanhas

Este artigo examina como as ameaças de cibersegurança escalaram dramaticamente durante a pandemia de COVID-19, destacando a vulnerabilidade crítica Log4Shell e defendendo uma metodologia de desenvolvimento "security-first".

Dados ao Serviço do Território: A Nova IRIG-Madeira

Dados ao Serviço do Território: A Nova IRIG-Madeira

A Waymotion desenvolveu e implementou uma nova Infraestrutura Regional de Informação Geográfica para a Região Autónoma da Madeira, criando um enquadramento moderno para a gestão da informação territorial baseado em normas internacionais abertas.