Airflow com Python: Orquestração de Pipelines de Dados
Aprenda a usar Apache Airflow com Python para orquestrar pipelines de dados, agendar DAGs, tratar falhas, monitorar execuções e montar um projeto de portfólio.
Apache Airflow aparece com frequência em vagas brasileiras de engenharia de dados, analytics engineering, plataforma, machine learning e automação. O motivo é simples: quando um script Python deixa de ser uma tarefa eventual e passa a rodar todo dia, em uma ordem específica, com dependências, retries, logs e alerta de falha, você precisa de orquestração. Rodar python etl.py no cron pode funcionar no começo, mas fica frágil quando o processo cresce.
Airflow resolve esse ponto organizando pipelines como DAGs: grafos direcionados acíclicos. Na prática, você descreve quais tarefas existem, em que ordem elas devem rodar, quando o fluxo deve ser agendado e o que acontece quando algo falha. Isso encaixa muito bem em projetos Python que buscam dados de APIs, validam arquivos, carregam tabelas, atualizam dashboards ou preparam bases para modelos.
Este guia mostra como pensar Airflow de forma prática, sem transformar um projeto pequeno em uma plataforma gigante. A ideia é construir um pipeline de dados com Python, validação, carga e monitoramento básico, conectando com temas que já importam para quem está montando portfólio: ETL com Python, Pandera para validação de dados, Docker em projetos Python, OpenTelemetry e observabilidade e vagas Python no Brasil.
Quando Airflow faz sentido
Airflow não é obrigatório para todo script. Se você tem uma automação simples, sem dependências e sem necessidade de histórico visual, cron, systemd timer, GitHub Actions ou um job agendado na nuvem podem resolver. A ferramenta começa a valer a pena quando existem várias etapas conectadas.
Use Airflow quando você precisa de:
- agendamento recorrente com histórico de execução;
- tarefas com dependências claras;
- retries automáticos quando uma API ou banco falha temporariamente;
- logs por etapa, não apenas um log gigante do script inteiro;
- backfill para reprocessar dias anteriores;
- visibilidade para outras pessoas do time;
- separação entre extração, validação, transformação e carga.
Um exemplo comum no Brasil é um pipeline que busca pedidos de um e-commerce, enriquece com dados de CRM, valida colunas obrigatórias, grava Parquet ou DuckDB e atualiza um dashboard comercial. Outro exemplo é consumir dados públicos, como bases do IBGE ou Banco Central, e gerar indicadores semanais para análise. Se o pipeline precisa ser explicado para uma pessoa de negócio ou revisado por outro dev, a interface do Airflow ajuda bastante.
Conceitos essenciais
Antes do código, vale entender quatro termos:
| Conceito | O que significa |
|---|---|
| DAG | Definição do fluxo e das dependências entre tarefas |
| Task | Uma etapa executável, como extrair API ou validar CSV |
| Operator | Classe que executa uma tarefa, como PythonOperator ou BashOperator |
| Schedule | Frequência de execução, por exemplo diária às 7h |
O erro mais comum é colocar toda a lógica dentro do arquivo da DAG. Isso até roda, mas vira manutenção difícil. O melhor padrão é deixar a DAG como orquestração e mover a lógica de negócio para módulos Python testáveis. Assim você consegue rodar testes com pytest sem subir o Airflow inteiro.
Estrutura de projeto recomendada
Uma estrutura pequena e profissional pode começar assim:
pipeline-vendas/
dags/
vendas_diarias.py
src/
pipeline_vendas/
__init__.py
extract.py
validate.py
transform.py
load.py
tests/
test_transform.py
docker-compose.yml
pyproject.toml
README.md
O diretório dags/ fica para o Airflow descobrir fluxos. O pacote src/pipeline_vendas/ concentra código reaproveitável. Essa separação melhora o portfólio porque mostra que você sabe diferenciar orquestração de regra de negócio.
Instale dependências em um ambiente isolado:
python -m venv .venv
source .venv/bin/activate
pip install apache-airflow pandas pandera httpx duckdb pytest
Em projetos reais, siga a matriz de versões do Airflow e use constraints oficiais. Para estudo local, Docker Compose costuma ser mais previsível do que instalar tudo diretamente na máquina. Se você ainda está montando base de ambiente, veja também ambientes virtuais em Python e uv como gerenciador de pacotes.
Extração como função Python
Comece com uma função simples e testável. Ela poderia consumir uma API interna, uma planilha exportada ou um endpoint público:
# src/pipeline_vendas/extract.py
from __future__ import annotations
import httpx
def extrair_pedidos(base_url: str, data: str) -> list[dict]:
resposta = httpx.get(
f"{base_url}/pedidos",
params={"data": data},
timeout=30,
)
resposta.raise_for_status()
return resposta.json()["items"]
Observe que a função não conhece Airflow. Ela recebe parâmetros, retorna dados e pode ser testada. O Airflow entra depois, chamando essa função no horário correto e registrando a execução.
Validação antes da transformação
Dados ruins precisam falhar cedo. Com Pandera, você declara um contrato mínimo:
# src/pipeline_vendas/validate.py
import pandas as pd
import pandera as pa
from pandera import Check, Column, DataFrameSchema
schema_pedidos = DataFrameSchema(
{
"pedido_id": Column(int, unique=True),
"cliente_id": Column(int),
"uf": Column(str, Check.str_length(2, 2)),
"valor": Column(float, Check.ge(0)),
"status": Column(str, Check.isin(["pago", "pendente", "cancelado"])),
},
strict=True,
coerce=True,
)
def validar_pedidos(registros: list[dict]) -> pd.DataFrame:
df = pd.DataFrame(registros)
return schema_pedidos.validate(df)
Essa etapa evita que a transformação aceite silenciosamente uma coluna ausente ou um valor negativo. Em um pipeline orquestrado, falhar cedo é bom: a DAG fica marcada como falha, o log mostra a causa e o time sabe que o dado de entrada precisa ser corrigido.
Transformação e carga
Depois da validação, transforme e carregue o resultado. Para um projeto local, DuckDB é uma boa escolha porque não exige servidor:
# src/pipeline_vendas/load.py
from pathlib import Path
import duckdb
import pandas as pd
def carregar_resumo_vendas(df: pd.DataFrame, destino: Path) -> int:
resumo = (
df[df["status"] == "pago"]
.groupby("uf", as_index=False)["valor"]
.sum()
.rename(columns={"valor": "receita"})
)
with duckdb.connect(str(destino)) as con:
con.execute("CREATE OR REPLACE TABLE receita_por_uf AS SELECT * FROM resumo")
return len(resumo)
Retornar uma contagem ajuda no log da tarefa. Em produção, você poderia carregar em PostgreSQL, BigQuery, Snowflake, S3, R2, Databricks ou outro destino. O princípio é o mesmo: cada função deve deixar claro o que recebeu, o que produziu e como falhou.
Criando a DAG
Agora a DAG apenas conecta as peças:
# dags/vendas_diarias.py
from __future__ import annotations
from datetime import datetime, timedelta
from pathlib import Path
from airflow.decorators import dag, task
from pipeline_vendas.extract import extrair_pedidos
from pipeline_vendas.load import carregar_resumo_vendas
from pipeline_vendas.validate import validar_pedidos
@dag(
dag_id="vendas_diarias_python",
start_date=datetime(2026, 5, 1),
schedule="0 7 * * *",
catchup=False,
default_args={"retries": 2, "retry_delay": timedelta(minutes=5)},
tags=["python", "dados", "vendas"],
)
def vendas_diarias():
@task
def extrair(data_interval_start=None) -> list[dict]:
data = data_interval_start.strftime("%Y-%m-%d")
return extrair_pedidos("https://api.exemplo.com", data)
@task
def validar(registros: list[dict]) -> str:
df = validar_pedidos(registros)
caminho = Path("/tmp/pedidos_validados.parquet")
df.to_parquet(caminho, index=False)
return str(caminho)
@task
def carregar(caminho: str) -> int:
import pandas as pd
df = pd.read_parquet(caminho)
return carregar_resumo_vendas(df, Path("/tmp/vendas.duckdb"))
carregar(validar(extrair()))
vendas_diarias()
Esse exemplo usa a TaskFlow API, que deixa o código mais legível do que encadear operadores manualmente. Para pipelines pequenos e médios, ela é suficiente. Para integrações com bancos, cloud e ferramentas específicas, Airflow também oferece operators e providers próprios.
Boas práticas que aparecem em entrevistas
Um projeto com Airflow fica mais forte quando você mostra decisões operacionais, não apenas uma DAG bonita. Inclua no README:
- como subir o ambiente local;
- qual é o schedule da DAG;
- quais variáveis de ambiente são necessárias;
- o que acontece quando uma tarefa falha;
- como reprocessar um dia específico;
- onde ficam logs e artefatos;
- quais testes cobrem transformação e validação.
Evite guardar senha no código ou no repositório. Use variables, connections, secrets manager ou variáveis de ambiente. Também evite depender de arquivos em /tmp para produção: no exemplo isso simplifica o tutorial, mas em ambiente real use storage durável.
Observabilidade e alertas
Airflow já dá histórico, status por task, duração e logs. Mesmo assim, pipelines críticos precisam de sinais adicionais. Registre contagens de entrada e saída, quantidade de linhas rejeitadas, tempo de cada etapa e nome do arquivo ou partição processada. Esses detalhes reduzem o tempo de investigação.
Um log útil diz algo como: pedidos_extraidos=1200, pedidos_validos=1194, pedidos_rejeitados=6, particao=2026-05-31. Um log ruim diz apenas processando dados. Se o pipeline alimenta área financeira, comercial ou produto, a diferença entre esses dois estilos aparece rapidamente.
Para times maiores, vale exportar métricas do Airflow para Prometheus, Grafana, Datadog ou outra ferramenta. A mesma mentalidade de logs, métricas e traces com OpenTelemetry se aplica aqui: você quer responder o que falhou, quando começou, quantas linhas foram afetadas e se o problema é recorrente.
Airflow no portfólio
Para quem busca vaga, um bom projeto de Airflow não precisa ser enorme. Melhor um pipeline pequeno, bem documentado e reprodutível do que uma pasta cheia de DAGs que ninguém consegue rodar. Um projeto forte poderia ser:
- extrair dados públicos brasileiros de uma API;
- validar schema com Pandera;
- salvar histórico em DuckDB ou Parquet;
- gerar uma tabela agregada;
- rodar diariamente no Airflow;
- incluir testes de transformação;
- documentar falhas simuladas e reprocessamento.
Isso conversa diretamente com vagas de engenharia de dados e analytics, porque demonstra Python, SQL, qualidade de dados, automação e operação. Também combina com projetos de portfólio Python para conseguir vaga e com páginas de engenharia de dados nas vagas Python.
Se o projeto evoluir para alto volume ou múltiplos serviços, pode fazer sentido combinar Python com outras linguagens. Times que lidam com ingestão concorrente, filas e workers podem usar Python para transformação e Go para worker pools e filas. Essa comparação mostra maturidade: você entende onde Python brilha e onde outra ferramenta pode complementar.
Checklist final
Antes de publicar ou apresentar seu pipeline, revise:
- a DAG tem
start_date,schedule,catchupe retries conscientes; - a lógica de negócio está fora do arquivo da DAG;
- transformação e validação têm testes;
- credenciais não aparecem no repositório;
- logs têm contagens e contexto;
- README explica como rodar e reprocessar;
- o destino dos dados é durável;
- falhas comuns são documentadas.
Airflow não torna um pipeline automaticamente confiável. Ele dá a estrutura para você declarar dependências, agendar execuções e enxergar falhas. A confiabilidade vem do conjunto: funções pequenas, validação de dados, testes, logs úteis, retries bem escolhidos e documentação honesta. Para quem trabalha com Python no Brasil, esse conjunto é um diferencial concreto em projetos internos, freelas, entrevistas e vagas de dados.
Equipe Python Brasil
Contribuidor do Python Brasil — Aprenda Python em Português