Cloud & Infraestrutura

Como Usar SQS em Profundidade: Standard, FIFO, DLQ e Visibility Timeout em Produção

8 min de leitura

Como Usar SQS em Profundidade: Standard, FIFO, DLQ e Visibility Timeout em Produção

SQS: Arquitetura e Diferenças Fundamentais AWS SQS (Simple Queue Service) é o serviço de fila mais maduro da AWS, essencial para desacoplar aplicações em arquiteturas distribuídas. Existem dois tipos principais: Standard e FIFO, cada um com garantias e características distintas que definem sua aplicação em produção. Standard Queue oferece throughput ilimitado e entrega at-least-once, mas sem garantia de ordem. Use quando velocidade é crítica e duplicações podem ser tratadas idempotentemente. FIFO Queue garante entrega exatamente uma vez (exactly-once) e preserva ordem, ideal para operações financeiras ou sequências críticas. A escolha impacta diretamente sua arquitetura de consumidores e tolerância a falhas. Implementação Prática: Standard vs FIFO Standard Queue Standard queues permitem envios rápidos sem validações de ordem. A chave aqui é o long polling com , reduzindo custos e latência. Mensagens processadas com sucesso devem ser deletadas explicitamente; falhas resultam em reprocessamento automático. FIFO Queue Em FIFO, o garante que mensagens do mesmo grupo (ex: mesmo usuário) sejam processadas sequencialmente. O

<h2>SQS: Arquitetura e Diferenças Fundamentais</h2>

<p>AWS SQS (Simple Queue Service) é o serviço de fila mais maduro da AWS, essencial para desacoplar aplicações em arquiteturas distribuídas. Existem dois tipos principais: <strong>Standard</strong> e <strong>FIFO</strong>, cada um com garantias e características distintas que definem sua aplicação em produção.</p>

<p><strong>Standard Queue</strong> oferece throughput ilimitado e entrega at-least-once, mas sem garantia de ordem. Use quando velocidade é crítica e duplicações podem ser tratadas idempotentemente. <strong>FIFO Queue</strong> garante entrega exatamente uma vez (exactly-once) e preserva ordem, ideal para operações financeiras ou sequências críticas. A escolha impacta diretamente sua arquitetura de consumidores e tolerância a falhas.</p>

<h2>Implementação Prática: Standard vs FIFO</h2>

<h3>Standard Queue</h3>

<pre><code class="language-python">import boto3

import json

from datetime import datetime

sqs = boto3.client(&#039;sqs&#039;)

queue_url = &#039;https://queue.amazonaws.com/123456789/my-standard-queue&#039;

Produzir mensagens

def send_message_standard(body, attributes=None):

response = sqs.send_message(

QueueUrl=queue_url,

MessageBody=json.dumps(body),

MessageAttributes=attributes or {}

)

return response[&#039;MessageId&#039;]

Consumir com polling

def consume_standard():

messages = sqs.receive_message(

QueueUrl=queue_url,

MaxNumberOfMessages=10,

WaitTimeSeconds=20, # Long polling

VisibilityTimeout=30

)

for msg in messages.get(&#039;Messages&#039;, []):

try:

body = json.loads(msg[&#039;Body&#039;])

process_message(body)

Deletar apenas após processamento bem-sucedido

sqs.delete_message(

QueueUrl=queue_url,

ReceiptHandle=msg[&#039;ReceiptHandle&#039;]

)

except Exception as e:

print(f&quot;Erro ao processar: {e}&quot;)

Não deletar = volta à fila após visibility timeout

def process_message(body):

print(f&quot;Processando: {body} às {datetime.now()}&quot;)</code></pre>

<p><strong>Standard queues</strong> permitem envios rápidos sem validações de ordem. A chave aqui é o <strong>long polling</strong> com <code>WaitTimeSeconds=20</code>, reduzindo custos e latência. Mensagens processadas com sucesso devem ser deletadas explicitamente; falhas resultam em reprocessamento automático.</p>

<h3>FIFO Queue</h3>

<pre><code class="language-python"># Produzir mensagens FIFO

def send_message_fifo(body, deduplication_id, group_id):

response = sqs.send_message(

QueueUrl=&#039;https://queue.amazonaws.com/123456789/my-fifo.fifo&#039;,

MessageBody=json.dumps(body),

MessageDeduplicationId=deduplication_id, # Garante idempotência

MessageGroupId=group_id # Preserva ordem por grupo

)

return response[&#039;MessageId&#039;]

Consumir FIFO respeitando ordem

def consume_fifo():

messages = sqs.receive_message(

QueueUrl=&#039;https://queue.amazonaws.com/123456789/my-fifo.fifo&#039;,

MaxNumberOfMessages=10,

WaitTimeSeconds=20,

VisibilityTimeout=60 # Geralmente maior que Standard

)

for msg in messages.get(&#039;Messages&#039;, []):

receipt_handle = msg[&#039;ReceiptHandle&#039;]

body = json.loads(msg[&#039;Body&#039;])

if process_order(body):

sqs.delete_message(

QueueUrl=&#039;https://queue.amazonaws.com/123456789/my-fifo.fifo&#039;,

ReceiptHandle=receipt_handle

)

def process_order(order):

Operação idempotente: pode ser executada múltiplas vezes

user_id = order[&#039;user_id&#039;]

amount = order[&#039;amount&#039;]

print(f&quot;Processando pedido {user_id}: R${amount}&quot;)

return True</code></pre>

<p>Em <strong>FIFO</strong>, o <code>MessageGroupId</code> garante que mensagens do mesmo grupo (ex: mesmo usuário) sejam processadas sequencialmente. O <code>MessageDeduplicationId</code> previne duplicatas automáticas em caso de retransmissão.</p>

<h2>Visibility Timeout e Dead Letter Queue (DLQ)</h2>

<h3>Visibility Timeout em Profundidade</h3>

<p>O <strong>visibility timeout</strong> é o período em que uma mensagem fica invisível após recebida. Se não for deletada nesse intervalo, retorna à fila para reprocessamento. Em produção, defina um valor maior que o tempo máximo de processamento esperado.</p>

<pre><code class="language-python"># Ajustar visibility timeout dinamicamente

def consume_with_dynamic_timeout():

messages = sqs.receive_message(

QueueUrl=queue_url,

MaxNumberOfMessages=10,

VisibilityTimeout=30

)

for msg in messages.get(&#039;Messages&#039;, []):

receipt_handle = msg[&#039;ReceiptHandle&#039;]

start = datetime.now()

try:

Processar mensagem

result = heavy_processing(msg[&#039;Body&#039;])

Se demorar muito, estender timeout

elapsed = (datetime.now() - start).total_seconds()

if elapsed &gt; 20:

sqs.change_message_visibility(

QueueUrl=queue_url,

ReceiptHandle=receipt_handle,

VisibilityTimeout=int(elapsed + 10)

)

sqs.delete_message(

QueueUrl=queue_url,

ReceiptHandle=receipt_handle

)

except Exception as e:

print(f&quot;Falha permanente: {e}&quot;)

Não fazer nada: deixar timeout expirar

def heavy_processing(body):

import time

time.sleep(5)

return json.loads(body)</code></pre>

<h3>Dead Letter Queue (DLQ)</h3>

<p>Configure uma DLQ na política de <strong>redrive</strong> para capturar mensagens que falham repetidamente. Isso evita loops infinitos e permite debugging posterior.</p>

<pre><code class="language-python"># Criar DLQ

dlq_response = sqs.create_queue(QueueName=&#039;my-dlq&#039;)

dlq_url = dlq_response[&#039;QueueUrl&#039;]

Obter ARN da DLQ

dlq_attrs = sqs.get_queue_attributes(QueueUrl=dlq_url, AttributeNames=[&#039;QueueArn&#039;])

dlq_arn = dlq_attrs[&#039;Attributes&#039;][&#039;QueueArn&#039;]

Configurar redrive policy na fila principal

sqs.set_queue_attributes(

QueueUrl=queue_url,

Attributes={

&#039;RedrivePolicy&#039;: json.dumps({

&#039;deadLetterTargetArn&#039;: dlq_arn,

&#039;maxReceiveCount&#039;: 3 # Após 3 tentativas, vai para DLQ

})

}

)

Consumir DLQ para análise

def process_dlq():

messages = sqs.receive_message(

QueueUrl=dlq_url,

MaxNumberOfMessages=10

)

for msg in messages.get(&#039;Messages&#039;, []):

print(f&quot;Mensagem morta: {msg[&#039;Body&#039;]}&quot;)

Log para análise ou reprocessamento manual

sqs.delete_message(QueueUrl=dlq_url, ReceiptHandle=msg[&#039;ReceiptHandle&#039;])</code></pre>

<p>Uma DLQ bem configurada é sua rede de segurança em produção. Monitore-a constantemente; mensagens na DLQ indicam bugs ou dados inválidos que requerem investigação.</p>

<h2>Otimizações e Padrões de Produção</h2>

<h3>Batch Processing e Métricas</h3>

<pre><code class="language-python">import logging

logger = logging.getLogger(__name__)

def batch_consumer(queue_url, worker_threads=5):

from concurrent.futures import ThreadPoolExecutor

def worker():

while True:

messages = sqs.receive_message(

QueueUrl=queue_url,

MaxNumberOfMessages=10,

WaitTimeSeconds=20,

VisibilityTimeout=60

)

if &#039;Messages&#039; not in messages:

continue

processed = 0

failed = 0

for msg in messages[&#039;Messages&#039;]:

try:

process_message(msg[&#039;Body&#039;])

sqs.delete_message(

QueueUrl=queue_url,

ReceiptHandle=msg[&#039;ReceiptHandle&#039;]

)

processed += 1

except Exception as e:

logger.error(f&quot;Falha: {e}&quot;, exc_info=True)

failed += 1

logger.info(f&quot;Batch: {processed} sucesso, {failed} falhas&quot;)

with ThreadPoolExecutor(max_workers=worker_threads) as executor:

for _ in range(worker_threads):

executor.submit(worker)</code></pre>

<p><strong>Práticas essenciais:</strong> use <strong>long polling</strong> (WaitTimeSeconds &gt; 0) para reduzir custos; processe em <strong>lotes</strong> para eficiência; implemente <strong>idempotência</strong> em consumidores; monitore <strong>ApproximateAgeOfOldestMessage</strong> para detectar atrasos.</p>

<blockquote><p><strong>Dica de Ouro:</strong> Em produção, sempre configure CloudWatch alarms para tamanho da fila, tempo de retenção de mensagens e contagem de mensagens na DLQ. Falhas silenciosas são piores que crashes detectáveis.</p></blockquote>

<h2>Conclusão</h2>

<p>Dominar SQS requer compreensão de três pilares: <strong>(1) escolher Standard ou FIFO baseado em garantias de ordem vs throughput</strong>; <strong>(2) configurar visibility timeout e DLQ apropriadamente para resiliência</strong>; <strong>(3) implementar consumidores idempotentes com processamento em lotes e monitoramento ativo</strong>. A transição para produção é segura quando você entende que filas desacoplam responsabilidades, não eliminam erros—eles apenas os tornam gerenciáveis.</p>

<h2>Referências</h2>

<ul>

<li><a href="https://docs.aws.amazon.com/sqs/" target="_blank" rel="noopener noreferrer">AWS SQS Developer Guide</a></li>

<li><a href="https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/best-practices-for-sqs.html" target="_blank" rel="noopener noreferrer">Best Practices for Amazon SQS</a></li>

<li><a href="https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/working-with-visibility-timeout.html" target="_blank" rel="noopener noreferrer">Understanding Visibility Timeout</a></li>

<li><a href="https://aws.amazon.com/blogs/compute/designing-event-driven-architectures-on-aws/" target="_blank" rel="noopener noreferrer">Designing Event-Driven Architectures on AWS - Builder&#039;s Guide</a></li>

</ul>

Comentários

Mais em Cloud & Infraestrutura

Como Usar ECS com Fargate: Task Definitions, Services e Service Discovery em Produção
Como Usar ECS com Fargate: Task Definitions, Services e Service Discovery em Produção

Fundamentos do ECS com Fargate: Arquitetura e Componentes O Amazon ECS (Elast...

S3 Avançado: Replication, Object Lock, Intelligent Tiering e S3 Select na Prática
S3 Avançado: Replication, Object Lock, Intelligent Tiering e S3 Select na Prática

S3 Replication: Garantindo Disponibilidade e Conformidade S3 Replication perm...

Dominando Lambda Avançado: Layers, Extensions, SnapStart e Cold Start em Projetos Reais
Dominando Lambda Avançado: Layers, Extensions, SnapStart e Cold Start em Projetos Reais

Entendendo Lambda Layers: Organização e Reutilização Lambda Layers são pacote...