APIs e Microsserviços

23 jun, 2026

Padrão Strangler Fig em Larga Escala: Modernização de Monolitos com Azure Front Door e API Management

Publicidade

A modernização de sistemas monolíticos legados apresenta um dos maiores riscos financeiros e operacionais na engenharia de software corporativa. A tentativa de reescrever a plataforma inteira em um único evento de transição (Big Bang rewrite) falha sistematicamente devido à complexidade oculta do domínio e à incapacidade de congelar o desenvolvimento de novas funcionalidades por anos. A implementação do padrão Strangler Fig anula esse risco ao permitir a substituição incremental e metódica dos componentes legados. Ao posicionar uma fachada de rede inteligente na borda da infraestrutura utilizando o Azure Front Door e o Azure API Management, os arquitetos interceptam o tráfego do cliente e o redirecionam para novos microsserviços à medida que são desenvolvidos. O sistema legado permanece em operação, encolhendo gradativamente até que toda a sua funcionalidade seja modernizada e ele possa ser desligado com segurança. Essa topologia garante entregas contínuas de valor, tolerância a falhas na migração e zero impacto perceptível para o usuário final durante a transição na nuvem do Azure.

Pré-requisitos

A orquestração dessa malha de roteamento transitória exige fluência em redes de distribuição de conteúdo (CDNs) e manipulação avançada de cabeçalhos HTTP. A infraestrutura como código deve ser declarada estritamente através do Terraform versão 1.7.0 ou superior, utilizando o provedor HashiCorp AzureRM versão 3.90.0. A Camada Anticorrupção (ACL) requer o Python 3.12, acoplado às bibliotecas azure-servicebus e motor relacional SQLAlchemy para interações diretas com o banco de dados legado. Privilégios administrativos na assinatura do Azure são necessários para gerenciar zonas DNS públicas e registrar certificados TLS/SSL no Azure Key Vault.

Passo a Passo

Fachada de Roteamento Global e Isolamento de DNS

A fundação do padrão Strangler inicia-se pela abstração absoluta do endereço de rede do sistema legado. Se as aplicações clientes (web ou mobile) comunicam-se diretamente com os IPs ou domínios originais do monolito, torna-se impossível redirecionar rotas específicas sem alterar o código do cliente. Provisionamos o Azure Front Door Premium para assumir o domínio corporativo oficial e atuar como o ponto de entrada global único. A justificativa arquitetônica reside na dissociação do cliente em relação à topologia de backend. O Front Door recebe as requisições na borda global da Microsoft, encerra a conexão TLS próxima ao usuário para reduzir a latência e encaminha o tráfego de volta para a origem legada através do backbone privado. Inicialmente, o Front Door é configurado com um roteamento de passagem (pass-through) total, onde 100% do tráfego atinge o sistema antigo inalterado. Isso estabelece a malha de controle necessária sem alterar o comportamento funcional da aplicação.

resource "azurerm_cdn_frontdoor_profile" "strangler_edge" {
  name                = "afd-enterprise-strangler"
  resource_group_name = var.resource_group_name
  sku_name            = "Premium_AzureFrontDoor"
}

resource "azurerm_cdn_frontdoor_endpoint" "global_ingress" {
  name                     = "api-enterprise-global"
  cdn_frontdoor_profile_id = azurerm_cdn_frontdoor_profile.strangler_edge.id
}
resource "azurerm_cdn_frontdoor_origin_group" "legacy_backend" {
  name                     = "legacy-monolith-group"
  cdn_frontdoor_profile_id = azurerm_cdn_frontdoor_profile.strangler_edge.id
  health_probe {
    interval_in_seconds = 60
    path                = "/healthcheck.aspx"
    protocol            = "Https"
    request_type        = "HEAD"
  }
  load_balancing {
    successful_samples_required = 1
  }
}
resource "azurerm_cdn_frontdoor_origin" "legacy_server" {
  name                           = "onpremise-monolith"
  cdn_frontdoor_origin_group_id  = azurerm_cdn_frontdoor_origin_group.legacy_backend.id
  enabled                        = true
  host_name                      = "legacy.internal.empresa.com"
  origin_host_header             = "api.empresa.com"
  certificate_name_check_enabled = false
}
resource "azurerm_cdn_frontdoor_route" "default_pass_through" {
  name                          = "catch-all-legacy"
  cdn_frontdoor_endpoint_id     = azurerm_cdn_frontdoor_endpoint.global_ingress.id
  cdn_frontdoor_origin_group_id = azurerm_cdn_frontdoor_origin_group.legacy_backend.id
  cdn_frontdoor_origin_ids      = [azurerm_cdn_frontdoor_origin.legacy_server.id]
  patterns_to_match             = ["/*"]
  supported_protocols           = ["Https"]
  https_redirect_enabled        = true
}

Como interceptamos caminhos funcionais granulares mais profundos no payload da requisição para roteá-los a novos microsserviços sem sobrecarregar a CDN global com regras de negócios voláteis?

Interceptação L7 e Estrangulamento via API Management

Delegamos a inspeção profunda de Camada 7 e o roteamento baseado em contexto provisionando o Azure API Management (APIM) logo atrás do Front Door. O Azure Front Door foca em segurança perimetral (WAF) e aceleração global, enquanto o APIM domina a transformação de requisições. O raciocínio técnico para empilhar essas duas soluções é a capacidade do APIM de executar políticas (Policies) em XML que podem reescrever URLs, extrair tokens JWT e converter formatos de carga útil (como XML legado para JSON moderno) em tempo real. Modificamos a rota do Front Door para apontar para o APIM. Dentro do APIM, configuramos uma operação específica, como /api/v1/billing, para ser roteada (estrangulada) para o novo microsserviço hospedado no Azure Container Apps. O APIM captura essa URI, traduz a chamada e a envia para a nova nuvem. Todas as demais requisições não mapeadas (catch-all) caem na política base do APIM e são encaminhadas para o monolito. Do ponto de vista do aplicativo móvel do cliente, a transição entre o código de 15 anos atrás e o contêiner recém-implantado é invisível.

Press enter or click to view image in full size

Diagrama de Sequência
resource "azurerm_api_management_api" "billing_facade" {
  name                = "billing-api"
  resource_group_name = var.resource_group_name
  api_management_name = azurerm_api_management.core.name
  revision            = "1"
  display_name        = "Faturamento Strangler API"
  path                = "api/v1/billing"
  protocols           = ["https"]
}

resource "azurerm_api_management_api_policy" "route_to_microservice" {
  api_name            = azurerm_api_management_api.billing_facade.name
  api_management_name = azurerm_api_management.core.name
  resource_group_name = var.resource_group_name
  # A política XML instrui o APIM a alterar o backend alvo exclusivamente para esta rota
  xml_content = <<XML
<policies>
    <inbound>
        <base />
        <set-backend-service base-url="https://app-billing-aca.internal.azurecontainerapps.io" />
        <rewrite-uri template="/billing" />
    </inbound>
    <backend>
        <base />
    </backend>
    <outbound>
        <base />
    </outbound>
    <on-error>
        <base />
    </on-error>
</policies>
XML
}

Quando o novo microsserviço de faturamento processa um pagamento de forma isolada, como ele notifica e atualiza o banco de dados do monolito para que as funcionalidades antigas de geração de relatórios operem sem apresentar dados estagnados?

Sincronização Reversa e Camada Anticorrupção (ACL)

Sincronizamos os sistemas implementando uma Camada Anticorrupção (Anti-Corruption Layer — ACL) baseada em eventos orientados pelo Azure Service Bus. O novo microsserviço jamais deve conectar-se diretamente ao banco de dados relacional legado para atualizar tabelas. O raciocínio arquitetônico vital dita que a criação de dependências diretas de banco de dados entre sistemas destrói a autonomia do microsserviço e polui o novo domínio com esquemas de dados obsoletos. A solução exige que o novo serviço emita um Evento de Domínio puro (exemplo: PaymentCompleted) em um tópico do Service Bus. Um worker assíncrono em Python, atuando estritamente como a ACL, consome este evento. O worker detém o conhecimento sujo sobre como o monolito funciona; ele traduz o JSON limpo do evento em comandos SQL complexos e atualiza o banco de dados legado (ou invoca endpoints SOAP antigos). Esta topologia blinda o novo ecossistema e garante que o monolito seja alimentado por consistência eventual, mantendo a integridade operacional da empresa durante os meses que a migração exigir.

import os
import json
import asyncio
import logging
from azure.servicebus.aio import ServiceBusClient
from azure.identity.aio import DefaultAzureCredential
from sqlalchemy import create_engine, text

logger = logging.getLogger("AntiCorruptionLayer")
class LegacyDatabaseAdapter:
    def __init__(self, connection_string: str):
        self.engine = create_engine(connection_string)
    def sync_payment_to_legacy(self, invoice_id: str, amount: float):
        # A ACL conhece as regras obscuras do monolito (ex: status_code 4 representa pago)
        query = text("""
            UPDATE tbl_Legacy_Invoices 
            SET AmountPaid = :amount, StatusCode = 4, LastModified = GETDATE()
            WHERE InvoiceReference = :invoice_id
        """)
        with self.engine.begin() as conn:
            conn.execute(query, {"amount": amount, "invoice_id": invoice_id})
            logger.info(f"Sincronização reversa concluída no monolito para a fatura {invoice_id}")
async def main():
    credential = DefaultAzureCredential()
    sb_client = ServiceBusClient(os.environ["SERVICEBUS_FQDN"], credential=credential)
    legacy_adapter = LegacyDatabaseAdapter(os.environ["LEGACY_DB_CONNECTION"])
    async with sb_client:
        receiver = sb_client.get_subscription_receiver(
            topic_name="billing-events", 
            subscription_name="acl-legacy-sync"
        )
        async with receiver:
            async for msg in receiver:
                try:
                    event_data = json.loads(str(msg))
                    if event_data.get("eventType") == "PaymentCompleted":
                        legacy_adapter.sync_payment_to_legacy(
                            event_data["invoiceId"], 
                            event_data["totalPaid"]
                        )
                    await receiver.complete_message(msg)
                except Exception as e:
                    logger.error(f"Falha na Camada Anticorrupção: {e}")
                    await receiver.abandon_message(msg)
if __name__ == "__main__":
    asyncio.run(main())

Se a camada de sincronização falhar ou o roteamento apresentar comportamento anômalo, como diagnosticamos falhas silenciosas ou inversões de cache que surgem subitamente durante essa complexa transição de estado?

Solução de Problemas Comuns

Uma disfunção primária na implantação do padrão Strangler manifesta-se através de erros HTTP 404 Resource Not Found intermitentes provenientes do API Management após a adição de novas regras de roteamento. Invariavelmente, a causa não está na inatividade do microsserviço de destino, mas no sufixo de reescrita da URI na política XML do APIM. Se a política de rewrite-uri não estiver configurada ou possuir barras à direita invertidas (trailing slashes), o APIM anexará o caminho da fachada inteira ao backend. Por exemplo, uma chamada para /api/v1/billing será enviada ao microsserviço como https://app-backend/api/v1/billing em vez do esperado https://app-backend/. Utilize o recurso “Test” no portal do APIM ativando a opção de “Trace” (Rastreamento) Ocp-Apim-Trace para inspecionar exatamente qual URL de backend o proxy montou no momento da interceptação.

Outro estrangulamento sistêmico envolve clientes recebendo cargas XML obsoletas do monolito mesmo após o APIM ter sido reconfigurado para rotear o tráfego para os novos microsserviços JSON. Esse sintoma de inversão aponta diretamente para o cache agressivo de borda no Azure Front Door. O Front Door frequentemente ignora as atualizações de topologia de backend do APIM porque o cache é baseado na URI exata da requisição. Se a resposta da rota /api/v1/billing do monolito foi armazenada em cache com um Time to Live (TTL) longo poucas horas antes do estrangulamento, a CDN não consultará o APIM até a expiração. A mitigação técnica obriga a execução de uma Purga de Cache (Cache Purge) explícita via CLI do Azure ou pipeline de CI/CD em todos os nós de borda globais no exato instante em que a política de roteamento L7 for alterada.

Conclusão

A triangulação arquitetônica empregando o Azure Front Door, o API Management e a malha orientada a eventos consolida uma via de modernização segura para débitos técnicos profundos. O padrão Strangler Fig protege a reputação corporativa e o fluxo de caixa, garantindo que refatorações gigantescas sejam percebidas pelo mercado externo apenas como melhorias graduais e invisíveis na performance da plataforma. O clímax dessa implementação culmina na obsolescência e eventual desligamento físico do servidor legado. Para ecossistemas que exigem segurança de tráfego interno (Leste-Oeste) durante a migração, a arquitetura pode ser estendida provisionando o Azure API Management injetado diretamente em uma Virtual Network (VNet Internal Mode), garantindo que a comunicação entre a fachada, os novos contêineres e os servidores on-premises flua estritamente através do Azure ExpressRoute.