☕ Um Café no Bellacosa Mainframe
Gostou do conteúdo? Ajude a manter o café quente, o COBOL compilando e o mainframe acordado. 😄
☕ Pague um café ao Bellacosa

Translate

Mostrar mensagens com a etiqueta Idempotência. Mostrar todas as mensagens
Mostrar mensagens com a etiqueta Idempotência. Mostrar todas as mensagens

segunda-feira, 27 de abril de 2026

💣🔥 LAB DE GUERRA — FINTECH NO z/OS: TPS REAL, LEDGER CONSISTENTE E MULTI-REGIÃO SEM ILUSÃO 🔥💣

 

Bellacosa Mainframe em Lab TPS 

💣🔥 LAB DE GUERRA — FINTECH NO z/OS: TPS REAL, LEDGER CONSISTENTE E MULTI-REGIÃO SEM ILUSÃO 🔥💣

Aqui não é slide. Aqui é produção simulada.
Você vai montar um fluxo que separa quem roda código de quem segura banco no ar.


⚙️ VISÃO DO LAB (ARQUITETURA)

👉 Dois mundos:

🔴 Região BR (CICS AOR)

  • Entrada da transação
  • Validação
  • Débito local (ledger consistente)

🔵 Região MX (CICS AOR)

  • Recebe evento assíncrono
  • Aplica crédito

⚫ TOR (Terminal Owning Region)

  • Entrada de carga (simulação TPS)

🧠 OBJETIVO DO LAB

Você vai provar na prática:

  • 💰 Ledger consistente localmente
  • ♻️ Idempotência salvando sua vida
  • 🔁 Assíncrono dominando multi-região
  • 📊 TPS ≠ Throughput (medido, não teórico)

📦 COMPONENTES

  • COBOL (CICS)
  • VSAM KSDS (ledger)
  • DB2 (controle/idempotência)
  • TSQ/TDQ (fila assíncrona simulando Kafka)
  • JCL (carga batch TPS)

🧾 1. LEDGER CONSISTENTE (COBOL + VSAM)

💣 Aqui não tem brincadeira: saldo é consistência forte local

Estrutura VSAM

ACCOUNT-ID PIC X(10)
BALANCE PIC S9(15)V99
LAST-UPDATE PIC X(26)

COBOL (CICS - débito)

EXEC CICS READ
FILE('LEDGER')
INTO(WS-ACCOUNT)
RIDFLD(WS-ACCOUNT-ID)
END-EXEC

IF WS-BALANCE < WS-AMOUNT
MOVE 'INSUFFICIENT' TO WS-STATUS
EXEC CICS ABEND END-EXEC
END-IF

SUBTRACT WS-AMOUNT FROM WS-BALANCE

EXEC CICS REWRITE
FILE('LEDGER')
FROM(WS-ACCOUNT)
END-EXEC

🔥 Isso aqui é o seu TPS real
👉 Só conta se COMMITOU


♻️ 2. IDEMPOTÊNCIA (DB2 — ANTI-DUPLICAÇÃO)

💣 Sem isso, retry vira fraude.

Tabela DB2

CREATE TABLE TX_CONTROL (
TX_ID VARCHAR(36) PRIMARY KEY,
STATUS VARCHAR(10),
CREATED_AT TIMESTAMP
);

Lógica COBOL

EXEC SQL
SELECT STATUS INTO :WS-STATUS
FROM TX_CONTROL
WHERE TX_ID = :WS-TX-ID
END-EXEC

IF SQLCODE = 0
MOVE 'DUPLICATE' TO WS-STATUS
GOBACK
END-IF

EXEC SQL
INSERT INTO TX_CONTROL VALUES (:WS-TX-ID, 'NEW', CURRENT TIMESTAMP)
END-EXEC

🔥 Resultado:

  • Retry seguro
  • Zero duplicação
  • TPS protegido

🔁 3. FLUXO ASSÍNCRONO (TSQ/TDQ)

💣 Aqui nasce a escalabilidade.

Após débito (BR)

EXEC CICS WRITEQ TS
QUEUE('TXQUEUE')
FROM(WS-EVENT)
END-EXEC

Consumidor (MX)

EXEC CICS READQ TS
QUEUE('TXQUEUE')
INTO(WS-EVENT)
END-EXEC

🔥 Tradução moderna:

Você acabou de simular Kafka no mainframe raiz.


🌍 4. MULTI-REGIÃO (SIMULADO)

💣 Não existe commit distribuído aqui.

Fluxo:

  1. BR debita (consistente)
  2. Evento vai para fila
  3. MX processa depois
  4. Reconciliação se falhar

👉 Isso evita:

  • lock global
  • latência absurda
  • TPS morto

📊 5. SIMULAÇÃO REAL — TPS vs THROUGHPUT

JCL de carga

//LOADTPS JOB ...
//STEP1 EXEC PGM=TXGEN
//SYSIN DD *
TPS=10000
DURATION=60
/*

Resultado esperado

MétricaValor
Requests/s10.000
TPS real2.500–4.000
Latência50–300ms
Retry5–15%

💣 Interpretação Bellacosa:

  • Throughput alto = sistema ocupado
  • TPS alto = sistema fazendo dinheiro acontecer

⚠️ TESTES DE CAOS (OBRIGATÓRIO)

👉 Derrube o consumidor (MX)

  • TPS local continua alto
  • Fila cresce

👉 Simule duplicação

  • Idempotência segura

👉 Force latência

  • TPS cai se você errar arquitetura

☠️ LIÇÃO FINAL

Sistema financeiro NÃO escala com tecnologia.
Escala com decisão arquitetural consciente.


🔥 FECHAMENTO (NÍVEL PRODUÇÃO)

Se você entendeu esse LAB, você já sabe:

  • Por que Kafka não salva arquitetura ruim
  • Por que consistência custa TPS
  • Por que assíncrono é obrigatório
  • Por que ledger não negocia

segunda-feira, 11 de setembro de 2023

📨 ALAN TURING E O MQ DOS AGENTES — A MENSAGEM CHEGOU DUAS VEZES

 

Bellacosa Mainframe e as mensagens em ia

☕ UM CAFÉ NO BELLACOSA MAINFRAME

📨 ALAN TURING E O MQ DOS AGENTES — A MENSAGEM CHEGOU DUAS VEZES

IBM MQ, agentes de IA, mensageria, filas, producers, consumers, delivery semantics, acknowledgements, commit, rollback, duplicate delivery, idempotência, ordering, correlation ID, message ID, poison messages, backout queues, dead-letter queues, retry, persistence, request/reply, COBOL, CICS, Db2 — e o dia em que Alan Turing descobriu que uma mensagem pode chegar duas vezes sem que ninguém tenha cometido o mesmo erro duas vezes.





🎬 PRÓLOGO — MAS EU JÁ FIZ ISSO!

03:17 da madrugada.

O telefone toca.

Nunca existe boa notícia às 03:17.

O operador atende.

— Produção.

Silêncio.

Depois:

— Temos dois pagamentos iguais.

O operador abre o terminal.

PAYMENT-ID.... P88271
VALUE......... 850.00
STATUS........ PROCESSED

Outra linha:

PAYMENT-ID.... P88271
VALUE......... 850.00
STATUS........ PROCESSED

O pequeno agente aparece na tela.

— Não fui eu!

Alan Turing entra no CPD carregando uma caneca de café.

— Interessante defesa.

— Professor, eu processei a mensagem uma única vez!

O operador consulta os logs.

03:16:51 GET MESSAGE
03:16:52 PROCESS PAYMENT
03:16:52 DB2 COMMIT OK
03:16:52 ...
03:16:53 AGENT RESTART
03:16:54 GET MESSAGE

Turing aponta para o intervalo.

— O que aconteceu entre o commit e a confirmação do consumo da mensagem?

Silêncio.

O administrador MQ olha para o administrador Db2.

O administrador Db2 olha para o programador COBOL.

O programador COBOL olha para o robô.

O robô olha para a porta.

Turing sorri.

— Acho que encontramos nosso próximo capítulo.

No quadro escreve:

PROCESSAR UMA MENSAGEM E CONFIRMAR QUE ELA FOI PROCESSADA NÃO SÃO NECESSARIAMENTE O MESMO EVENTO.

Bem-vindo ao MQ dos Agentes.



📨 CAPÍTULO 1 — MENSAGERIA COMEÇA COM UMA IDEIA MUITO SIMPLES

Imagine dois programas.

PROGRAMA-A

precisa pedir alguma coisa para:

PROGRAMA-B

Uma possibilidade seria A chamar B diretamente.

A ───────────────► B

Mas isso cria algumas dependências.

B precisa estar disponível.

A talvez precise esperar.

A precisa saber onde B está.

Se B estiver sobrecarregado, A sofre junto.

Mensageria introduz um intermediário.

A
│
▼
QUEUE
│
▼
B

A produz uma mensagem.

B consome depois.

Temos dois papéis clássicos:

PRODUCER

e:

CONSUMER.

O producer produz.

O consumer consome.

No meio:

QUEUE.

Simples.

Até produção começar.



📬 CAPÍTULO 2 — UMA FILA É UMA CAIXA POSTAL

Para o programador COBOL iniciante, imagine uma caixa postal.

O remetente coloca:

PEDIDO 12345

na caixa.

Ele não precisa esperar o funcionário responsável aparecer.

Depois o consumidor pega a mensagem.

PUT
↓
QUEUE
↓
GET

No universo IBM MQ podemos imaginar conceitualmente operações como:

MQPUT

e:

MQGET.

O produtor coloca.

O consumidor recupera.

Isso permite:

desacoplamento
processamento assíncrono
absorção de picos
integração entre plataformas
resiliência

Nosso agente pode agora receber trabalho através de mensagens.



🤖 CAPÍTULO 3 — O AGENTE VIROU CONSUMIDOR

Imagine:

CUSTOMER.EVENTS

recebendo:

CUSTOMER_UPDATED

Nosso agente escuta essa fila.

Chega:

CUSTOMER_ID = 12345
EVENT       = ADDRESS_CHANGED

O agente:

1. recebe
2. interpreta
3. consulta Db2
4. aplica regras
5. talvez chama ferramentas
6. produz resultado

Perfeito.

Mas aparece a primeira pergunta importante:

Quando podemos considerar essa mensagem realmente processada?

Quando o agente começou?

Não.

Quando terminou o raciocínio?

Talvez não.

Quando atualizou o Db2?

Ainda precisamos pensar.

Quando confirmou o consumo?

Agora estamos chegando perto do problema.



✉️ CAPÍTULO 4 — TODA MENSAGEM PRECISA DE IDENTIDADE

No JES2 dos Agentes aprendemos:

RUN-ID.

Agora precisamos identificar mensagens.

Conceitualmente:

MESSAGE-ID

Pode existir também:

CORRELATION-ID.

Imagine:

MESSAGE-ID..... M000881
CORRELATION-ID. C000042
RUN-ID......... A004821

Esses identificadores respondem perguntas diferentes.

MESSAGE-ID

Qual mensagem é esta?

CORRELATION-ID

A qual conversa, fluxo ou solicitação ela pertence?

RUN-ID

Qual execução do agente está processando?

Isso será ouro para observabilidade.


🔗 CAPÍTULO 5 — CORRELATION ID: ENCONTRE A CONVERSA NO MEIO DO CAOS

Imagine:

REQUEST
MESSAGE-ID M100
CORREL-ID C500

O serviço responde:

RESPONSE
MESSAGE-ID M101
CORREL-ID C500

São mensagens diferentes.

Mas pertencem à mesma conversa.

Em sistemas distribuídos isso é extremamente útil.

Podemos seguir:

USER REQUEST
     ↓
CICS
     ↓
MQ
     ↓
AGENT
     ↓
Db2
     ↓
ANOTHER QUEUE

Tudo associado a:

CORRELATION-ID C500.

Quando alguém pergunta:

O que aconteceu com a solicitação do cliente?

não precisamos procurar agulha no palheiro.


📦 CAPÍTULO 6 — A MENSAGEM PODE SOBREVIVER AO CONSUMIDOR

Aqui está uma das grandes vantagens de mensageria confiável.

O producer envia.

PUT MESSAGE

O consumer está desligado.

A mensagem pode permanecer na fila conforme sua configuração e características.

Depois:

CONSUMER START

Ele processa.

Isso é muito diferente de uma chamada síncrona simples.

No mundo dos agentes isso é poderoso.

O LLM pode estar indisponível.

O worker pode reiniciar.

A aplicação pode sofrer manutenção.

A mensagem continua aguardando.

Mas agora surge uma pergunta:

Quanto tempo?


⏰ CAPÍTULO 7 — MENSAGENS TAMBÉM ENVELHECEM

Olha quem voltou.

Nosso amigo do Db2:

TEMPO.

Imagine:

MESSAGE CREATED:
10:00

O consumidor consegue processar:

14:00.

Tecnicamente a mensagem chegou.

Mas ainda faz sentido?

Talvez seja:

GENERATE MONTHLY REPORT

Sem problema.

Talvez seja:

CUSTOMER IS CURRENTLY LOGGED IN

Quatro horas depois?

Provavelmente inútil.

Logo mensagens também possuem:

AGE
EXPIRY
BUSINESS VALIDITY.

O MQ dos Agentes encontra o Db2 dos Agentes.

Não basta perguntar:

A mensagem chegou?

Pergunte:

Ela ainda significa alguma coisa quando chegou?


💥 CAPÍTULO 8 — A MENSAGEM CHEGOU DUAS VEZES

Finalmente chegamos ao monstro.

Imagine:

GET M001

O agente processa.

INSERT PAYMENT
COMMIT

Tudo certo.

Mas antes de completar adequadamente o ciclo de consumo:

CRASH.

Quando volta, dependendo da arquitetura e semântica empregada, a mensagem pode estar novamente disponível.

GET M001

O agente grita:

— Eu já processei isso!

A infraestrutura responde:

— Prove.

😂

Bem-vindo à possibilidade de:

REDELIVERY.


🧠 CAPÍTULO 9 — POR QUE DUPLICATAS EXISTEM?

Porque sistemas distribuídos possuem pontos de falha.

Considere:

MESSAGE
↓
PROCESS
↓
DATABASE UPDATE
↓
ACKNOWLEDGE

Agora imagine falha exatamente aqui:

DATABASE UPDATE
↓
COMMIT
↓
💀 CRASH
↓
ACKNOWLEDGE

Do ponto de vista do banco:

SUCCESS.

Do ponto de vista da mensageria:

NÃO SEI SE ELE TERMINOU.

O sistema possui duas escolhas ruins.

Escolha A

Assumir que processou.

Pode perder mensagem.

Escolha B

Entregar novamente.

Pode duplicar processamento.

Sistemas confiáveis frequentemente preferem não perder trabalho.

Então seu consumidor precisa estar preparado para duplicatas quando a semântica e arquitetura permitirem redelivery.


🔁 CAPÍTULO 10 — AT-LEAST-ONCE

Uma semântica comum em sistemas de mensageria e processamento distribuído é:

AT-LEAST-ONCE

Ou seja:

A mensagem será processada pelo menos uma vez.

Isso pode significar:

1

ou:

2

ou, em situações problemáticas:

mais.

Então:

AT-LEAST-ONCE

não significa:

EXACTLY-ONCE.

Se o efeito da mensagem não puder acontecer duas vezes, precisamos projetar proteção.


🎯 CAPÍTULO 11 — EXACTLY-ONCE É O UNICÓRNIO DA DUNGEON

Todo mundo quer:

EXACTLY ONCE.

A mensagem chega uma vez.

É processada uma vez.

O efeito acontece uma vez.

Perfeito.

Mas sistemas distribuídos possuem:

falhas
timeouts
restarts
partições
retries

E cada fronteira transacional complica o problema.

Se MQ e Db2 participam de uma unidade coordenada adequadamente, podemos obter garantias transacionais fortes em cenários específicos.

Mas quando nosso agente chama:

Db2
REST API
email
LLM
CRM SaaS
payment service

a conversa muda.

Nem todos participam da mesma transação.

Por isso é perigoso jogar:

EXACTLY-ONCE

num slide como se fosse magia.


🛡️ CAPÍTULO 12 — IDEMPOTÊNCIA ENTRA COM UMA ESPADA

A solução prática frequentemente passa por:

IDEMPOTÊNCIA.

Uma operação idempotente pode ser repetida sem produzir efeitos adicionais indesejados depois da primeira aplicação bem-sucedida.

Exemplo perigoso:

ADD R$ 100 TO BALANCE

Execute duas vezes:

+100
+100

Resultado diferente.

Agora imagine:

SET PAYMENT P123 STATUS = PROCESSED

Executar novamente pode ser inofensivo dependendo da regra.

Ou:

PROCESS PAYMENT
WHERE PAYMENT_ID = P123
AND STATUS = PENDING

Depois da primeira execução:

STATUS = PROCESSED.

A segunda encontra:

NOT PENDING.

Nada acontece.

Muito melhor.


🪪 CAPÍTULO 13 — IDEMPOTENCY KEY

Outra técnica:

IDEMPOTENCY-KEY.

Exemplo:

IDEMPOTENCY-KEY = ORDER-9981-PAYMENT

Antes de executar:

SELECT STATUS
FROM PROCESSED_MESSAGES
WHERE IDEMPOTENCY_KEY = :KEY;

Se já existe:

ALREADY PROCESSED

não repetimos o efeito.

Se não existe:

PROCESS
STORE KEY
COMMIT

O detalhe crucial é tornar essa proteção suficientemente atômica para impedir dois consumidores concorrentes de passarem pela verificação simultaneamente.

Porque senão:

AGENT-A: não existe!
AGENT-B: não existe!

AGENT-A: processa!
AGENT-B: processa!

Parabéns.

Construímos uma deduplicação que duplica.

😂


🔐 CAPÍTULO 14 — MQ E Db2 PRECISAM CONVERSAR SOBRE COMMIT

Agora chegamos ao terreno favorito do mainframe.

Imagine:

MQGET
↓
UPDATE Db2
↓
COMMIT

Queremos que o consumo da mensagem e a alteração no banco tenham comportamento consistente.

Idealmente, dentro de um desenho transacional apropriado:

GET MESSAGE
+
UPDATE DATABASE
+
COMMIT

fazem parte de uma unidade lógica coerente.

Se falhar:

ROLLBACK.

A alteração do banco não fica pela metade e a mensagem pode permanecer disponível conforme a unidade de trabalho.

Esse é exatamente o tipo de problema que mainframes resolvem há décadas.


🧱 CAPÍTULO 15 — UNIT OF WORK VOLTOU

Nosso velho amigo:

UOW

Unit of Work.

Conceitualmente:

BEGIN UOW

GET MESSAGE
UPDATE DB2
INSERT AUDIT

COMMIT UOW

Se:

UPDATE DB2

falhar:

ROLLBACK.

O importante é definir claramente:

Quais efeitos pertencem à mesma unidade de consistência?

Para agentes, isso é essencial.

Porque eles tendem a fazer muitas coisas.


☠️ CAPÍTULO 16 — O PROBLEMA DAS AÇÕES EXTERNAS

Nosso agente:

GET MESSAGE
↓
UPDATE Db2
↓
SEND EMAIL
↓
CALL PAYMENT API
↓
POST MESSAGE

Rollback?

Db2:

— Posso ajudar.

MQ:

— Também.

E-mail:

— Já enviei.

API externa:

— Já cobrei.

Internet:

— Boa sorte.

😂

Essa é a fronteira entre transações locais/coordenadas e efeitos distribuídos externos.

Você precisa pensar em:

idempotência
compensação
outbox
inbox
deduplicação
reconciliação

e não simplesmente:

ROLLBACK EVERYTHING.

📤 CAPÍTULO 17 — O OUTBOX PATTERN

Imagine que precisamos:

UPDATE ORDER

e depois publicar:

ORDER_COMPLETED.

Problema clássico:

UPDATE Db2
COMMIT

CRASH

SEND MESSAGE

O pedido mudou.

A mensagem nunca saiu.

Ou:

SEND MESSAGE

CRASH

UPDATE Db2

Mensagem diz que aconteceu.

Banco diz que não.

Uma abordagem conhecida é o:

TRANSACTIONAL OUTBOX.

Dentro da mesma transação do banco:

UPDATE ORDER

INSERT INTO OUTBOX
   ORDER_COMPLETED

COMMIT

Depois outro processo publica registros da outbox.

Assim a intenção de publicar fica persistida junto com a alteração de negócio.

Ainda precisamos tratar duplicatas na publicação.

Mas removemos uma janela perigosa.


📥 CAPÍTULO 18 — INBOX PATTERN

Do outro lado podemos manter registro das mensagens consumidas.

INBOX
────────────────
MESSAGE_ID
PROCESSED_AT
STATUS

Chega:

M001.

Verificamos.

Não existe.

Processamos e registramos.

Chega novamente:

M001.

Existe.

DUPLICATE

Ignoramos ou retornamos o resultado anterior, conforme a aplicação.

Temos então:

OUTBOX

para publicação confiável e:

INBOX

para consumo controlado.


🧪 CAPÍTULO 19 — A MENSAGEM VENENOSA

Imagine:

MESSAGE M666

Chega.

Consumer tenta.

FAIL.

Volta.

Tenta.

FAIL.

Volta.

FAIL.

E continua:

FAIL
FAIL
FAIL
FAIL
FAIL

Talvez a mensagem tenha:

formato inválido
campo impossível
versão incompatível
regra não suportada
dados corrompidos

Ela nunca funcionará sem intervenção.

Chamamos informalmente esse tipo de caso de:

POISON MESSAGE.

Nosso agente não deveria ficar mastigando veneno eternamente.


☠️ CAPÍTULO 20 — BACKOUT QUEUE

Em ambientes IBM MQ, podemos projetar tratamento para mensagens que repetidamente causam rollback/backout.

Depois de determinado limite:

BACKOUT COUNT > THRESHOLD

a aplicação pode encaminhar a mensagem para uma:

BACKOUT QUEUE.

Assim:

NORMAL QUEUE

continua processando mensagens saudáveis.

E a problemática vai para investigação.

Conceitualmente:

QUEUE
  │
  ▼
CONSUMER
  │
  ├── SUCCESS → DONE
  │
  └── FAIL
       │
       ▼
    RETRY
       │
       ▼
 THRESHOLD?
   │       │
  NO      YES
   │       │
 retry     ▼
       BACKOUT QUEUE

Isso impede que uma única mensagem bloqueie eternamente o fluxo.


⚰️ CAPÍTULO 21 — DEAD-LETTER QUEUE NÃO É EXATAMENTE A MESMA COISA

Aqui precisamos separar conceitos.

Uma:

DEAD-LETTER QUEUE

é tradicionalmente associada a mensagens que o sistema não consegue entregar ou encaminhar ao destino esperado por determinados problemas de entrega.

Uma:

BACKOUT QUEUE

pode ser usada pela aplicação para mensagens que foram entregues, mas falham repetidamente durante processamento e sofrem backout.

No discurso moderno muita gente usa “DLQ” genericamente para qualquer fila de mensagens problemáticas.

Mas no universo IBM MQ a distinção operacional é útil.

O mainframeiro olha e diz:

Nome correto evita reunião de duas horas.


🔁 CAPÍTULO 22 — RETRY PRECISA TER CÉREBRO

Falhou.

Tentamos novamente?

Depende.

Erro:

HTTP 503

Talvez.

Erro:

INVALID CUSTOMER ID

Provavelmente não.

Erro:

TIMEOUT

Talvez.

Erro:

SCHEMA VERSION UNSUPPORTED

Repetir cem vezes provavelmente produzirá cem fracassos.

Portanto:

RETRYABLE ERROR

e:

NON-RETRYABLE ERROR

deveriam ser tratados diferentemente.

Retry não é religião.

É política.


⏳ CAPÍTULO 23 — EXPONENTIAL BACKOFF

Imagine 10.000 agentes.

Serviço externo cai.

Todos tentam novamente:

NOW.

O serviço tenta recuperar.

Dez mil chamadas chegam.

Ele cai novamente.

Chamamos isso de:

RETRY STORM.

Uma estratégia:

1s
2s
4s
8s
16s

é exponential backoff.

Adicione:

JITTER

para não fazer todos acordarem exatamente juntos.

4.1s
3.7s
4.8s

Agora reduzimos o efeito manada.

WLM agradece.


🚂 CAPÍTULO 24 — E SE AS MENSAGENS CHEGAREM FORA DE ORDEM?

Imagine:

M1:
CUSTOMER_CREATED

depois:

M2:
CUSTOMER_BLOCKED.

Queremos:

M1 → M2.

Mas o consumidor observa:

M2 → M1.

Agora pode concluir:

Não existe cliente para bloquear.

Depois cria o cliente.

Resultado:

ACTIVE.

Mas deveria estar:

BLOCKED.

O conteúdo estava correto.

As mensagens estavam corretas.

A ordem estava errada.

Mais um monstro.


🔢 CAPÍTULO 25 — SEQUÊNCIA TAMBÉM É DADO

Podemos adicionar:

ENTITY-ID...... CUSTOMER-123
SEQUENCE....... 42

Depois:

ENTITY-ID...... CUSTOMER-123
SEQUENCE....... 43.

O consumidor recebe 43 antes de 42.

Pode:

esperar
reordenar
rejeitar
reconciliar

dependendo da arquitetura.

Mas precisa saber que existe ordem.

Sem informação de sequência, talvez seja impossível perceber o problema.


🧩 CAPÍTULO 26 — ORDEM GLOBAL É CARA E MUITAS VEZES DESNECESSÁRIA

Precisamos de todas as mensagens do sistema inteiro em ordem?

Provavelmente não.

Talvez precisemos apenas manter ordem por:

CUSTOMER-ID

ou:

ORDER-ID

ou:

ACCOUNT-ID.

Isso permite paralelismo entre entidades diferentes.

CUSTOMER A → ordered
CUSTOMER B → ordered
CUSTOMER C → ordered

mas A, B e C podem ser processados simultaneamente.

O segredo é perguntar:

Qual é a menor fronteira dentro da qual a ordem realmente importa?


🕰️ CAPÍTULO 27 — ATRASADA NÃO SIGNIFICA FORA DE ORDEM

Outra distinção.

Uma mensagem pode chegar:

30 minutos atrasada

mas ainda na ordem correta.

Ou:

100 ms depois

mas fora de ordem em relação a outra.

Temos conceitos diferentes:

LATENCY
ORDERING
FRESHNESS.

Não misture.

O Db2 dos Agentes nos ensinou:

dado tem idade.

O MQ acrescenta:

a notícia sobre o dado também tem idade.


📰 CAPÍTULO 28 — EVENT TIME E PROCESSING TIME

Imagine evento:

EVENT_TIME:
10:00:01

Chega ao consumidor:

PROCESSING_TIME:
10:00:09.

São tempos diferentes.

Isso pode ser extremamente relevante.

Se o agente analisa:

O que aconteceu às 10:00?

precisa considerar:

EVENT TIME.

Se pergunta:

Quando processamos?

usa:

PROCESSING TIME.

Misturar os dois pode gerar análises absurdas.


🤖 CAPÍTULO 29 — O AGENTE PRECISA SABER QUE O EVENTO NÃO É O ESTADO ATUAL

Chega mensagem:

10:00
CUSTOMER_STATUS_CHANGED
ACTIVE → BLOCKED

Nosso agente recebe às:

10:10.

Antes de executar ação crítica, talvez precise consultar Db2.

Porque às:

10:05

o cliente pode ter sido:

UNBLOCKED.

Então a mensagem descreve:

ALGO QUE ACONTECEU

e não necessariamente:

COMO O MUNDO ESTÁ AGORA.

Essa distinção é gigantesca.

EVENT ≠ CURRENT STATE.


🗄️ CAPÍTULO 30 — MQ E Db2 CONTAM HISTÓRIAS DIFERENTES

Db2 frequentemente responde:

Qual é o estado armazenado?

MQ frequentemente transporta:

Algo aconteceu.

Exemplo:

Db2:
STATUS = ACTIVE

Evento antigo:

CUSTOMER_BLOCKED.

Se o agente tratar o evento antigo como estado atual:

problema.

Por isso, para ações críticas:

EVENT
↓
INTERPRET
↓
READ CURRENT STATE
↓
REVALIDATE
↓
ACT.

Nosso princípio do Db2 dos Agentes volta novamente.


🔄 CAPÍTULO 31 — EVENTUAL CONSISTENCY

Em sistemas distribuídos, diferentes componentes podem não refletir a mesma mudança exatamente no mesmo instante.

Imagine:

SYSTEM A
STATUS = BLOCKED

Evento viaja.

Enquanto isso:

SYSTEM B
STATUS = ACTIVE.

Alguns milissegundos ou segundos depois:

SYSTEM B
STATUS = BLOCKED.

Durante esse intervalo:

A ≠ B.

Isso não significa necessariamente corrupção.

Pode ser uma consequência do modelo de propagação.

Agentes precisam compreender isso.

Dois sistemas podem temporariamente apresentar visões diferentes.

Lembra dos dois agentes do Db2?

Eles voltaram.


📊 CAPÍTULO 32 — OBSERVABILIDADE DA FILA

Nosso SDSF dos Agentes ganha novos campos.

Imagine:

QUEUE........ CUSTOMER.EVENTS
DEPTH........ 18,442

OLDEST MSG... 00:07:31
PUT RATE..... 920/s
GET RATE..... 710/s

CONSUMERS.... 24
BACKOUTS..... 17
RETRIES...... 2,881

Agora conseguimos enxergar:

QUEUE DEPTH

Mas profundidade sozinha não basta.

18 mil mensagens pode ser terrível.

Ou normal.

Precisamos de contexto.

Talvez mais importante seja:

OLDEST MESSAGE AGE.

Se a fila cresce e a mensagem mais velha envelhece:

temos backlog real.


📈 CAPÍTULO 33 — PRODUCER MAIS RÁPIDO QUE CONSUMER

Imagine:

PRODUCER = 1000 msg/s
CONSUMER = 700 msg/s

Diferença:

+300 msg/s.

Depois de um minuto:

18,000 messages

Depois de uma hora:

1,080,000.

A fila absorve pico.

Mas não derrota matemática.

😂

Se a entrada continuamente supera a saída:

BACKLOG ↑
LATENCY ↑
MESSAGE AGE ↑

Precisamos:

mais consumers
mais capacidade
reduzir trabalho
priorizar
aplicar backpressure

WLM aparece novamente.


🚦 CAPÍTULO 34 — BACKPRESSURE

Se consumidores não conseguem acompanhar produtores, precisamos evitar crescimento ilimitado.

Isso pode envolver:

rate limiting
quotas
producer throttling
queue limits
load shedding
priority

Mensageria desacopla componentes.

Mas desacoplamento não significa capacidade infinita.

Fila é amortecedor.

Não buraco negro.


🧰 CAPÍTULO 35 — CHECKLIST DO MQ DOS AGENTES

Antes de colocar um agente consumindo mensagens, responda:

1. Quem produz?

PRODUCER?

2. Quem consome?

CONSUMER?

3. A mensagem é persistente quando necessário?

Defina de acordo com criticidade.

4. Ela pode ser entregue novamente?

Projete assumindo que sim quando sua semântica permitir.

5. O processamento é idempotente?

Se não, por quê?

6. Existe idempotency key?

Defina.

7. Existe MESSAGE-ID?

Sempre saiba qual mensagem está tratando.

8. Existe CORRELATION-ID?

Rastreie o fluxo.

9. A ordem importa?

Defina a fronteira.

10. Existe sequence number?

Quando necessário.

11. A mensagem expira?

Defina validade.

12. Existe retry?

Classifique erros.

13. Existe backoff?

Evite tempestades.

14. Existe poison message handling?

Tenha backout ou quarentena adequada.

15. Existe DLQ?

Monitore.

16. A mensagem representa evento ou estado?

Não confunda.

17. Precisa revalidar no Db2?

Para ações críticas, provavelmente.

18. O commit inclui quais recursos?

Defina UOW.

19. Existem efeitos externos?

Planeje idempotência ou compensação.

20. Conseguimos provar o que aconteceu?

Logs, traces, IDs e timestamps.


🥚 EASTER EGG — A MENSAGEM IMORTAL

04:12.

O operador percebe:

BACKOUT COUNT = 847.

— Professor...

Turing aproxima-se.

MESSAGE-ID = M666

— Há quanto tempo?

FIRST DELIVERY:
1999-12-31 23:59:58

Silêncio.

O programador COBOL arregala os olhos.

— Isso está tentando processar desde o bug do milênio?

O administrador MQ responde:

— Ninguém teve coragem de apagar.

O pequeno robô pergunta:

— O que ela contém?

Abrem.

CUSTOMER-ID = 000000001
ACTION      = MIGRATE
FORMAT      = VERSION-0

Turing olha.

— Algum consumidor suporta versão zero?

Todos:

— Não.

— Então por que continuam tentando?

Silêncio.

O operador responde:

— Retry policy.

Turing pega o café.

— Qual?

RETRY = FOREVER.

Turing fecha os olhos.

No fundo do CPD alguém sussurra:

Ela não é uma mensagem... agora ela é patrimônio histórico.

😂


🧬 CAPÍTULO 36 — NOSSO MAINFRAME DOS AGENTES GANHOU SISTEMA NERVOSO

Nossa arquitetura agora possui:

RACF
↓
QUEM PODE?
PF3
↓
POSSO PARAR?
SDSF
↓
O QUE ESTÁ FAZENDO?
MAXCC
↓
FUNCIONOU?
WLM
↓
QUEM RECEBE RECURSOS?
JES2
↓
QUEM COMEÇA E QUANDO?
CICS
↓
QUANTO TEMPO O HUMANO PODE ESPERAR?
Db2
↓
QUAL REALIDADE O AGENTE ESTÁ VENDO?

E agora:

MQ
↓
COMO A NOTÍCIA VIAJA ENTRE OS AGENTES?

Começamos a montar algo muito interessante.


🏰 CAPÍTULO 37 — O SISTEMA OPERACIONAL CONCEITUAL DOS AGENTES

Turing desenha:

                        HUMANO
                           │
                           ▼
                        CICS
                           │
               ┌───────────┴───────────┐
               │                       │
               ▼                       ▼
             AGENT                    MQ
               │                       │
               │                  ┌────┴────┐
               │                  ▼         ▼
               │               AGENT-B   AGENT-C
               │                  │         │
               └──────────┬───────┴─────────┘
                          ▼
                         Db2

Acima:

JES2
SCHEDULING

Ao redor:

WLM
CAPACITY

Na porta:

RACF
AUTHORITY

Na sala de operações:

SDSF
OBSERVABILITY

E sobre as mensagens:

MESSAGE-ID
CORRELATION-ID
SEQUENCE
TIMESTAMP
VERSION

Agora agentes não são apenas pequenos cérebros isolados.

Eles formam:

UM SISTEMA DISTRIBUÍDO.

E sistemas distribuídos possuem regras próprias.


🧠 CAPÍTULO 38 — O PROGRAMADOR COBOL TEM OUTRA VANTAGEM INESPERADA

Para muita gente:

event-driven architecture
message queues
async processing
retries

parecem invenções moderníssimas.

O mainframeiro olha para MQ e diz:

Sente-se, jovem.

😂

Porque aplicações corporativas trabalham com:

mensageria
filas
commit
rollback
correlation
persistence
backout
recovery

há décadas.

Claro que tecnologias modernas acrescentaram:

cloud
Kafka
microservices
containers
serverless
agents
LLMs.

Mas a pergunta fundamental continua:

Como dois componentes independentes trocam trabalho sem transformar cada falha em catástrofe?

Essa pergunta é antiga.

E continua excelente.


☕ CAPÍTULO 39 — O AGENTE PRECISA SER DESCONFIADO

Um consumidor robusto não deveria pensar:

Recebi uma mensagem. Vou obedecer.

Deveria perguntar:

Quem enviou?
Posso confiar?
Qual schema?
Qual versão?
Já processei?
Está na ordem?
Ainda é válida?
Tenho autorização?
Preciso consultar o estado atual?
Posso executar duas vezes?
Como confirmo?
Como desfaço?

Isso parece paranoia.

Em produção chamamos de:

ENGENHARIA.


🎭 CAPÍTULO 40 — EVENTO NÃO É ORDEM

Outra regra importante para agentes.

Mensagem:

CUSTOMER_CHANGED_ADDRESS

significa:

O endereço mudou.

Não significa automaticamente:

Faça alguma coisa perigosa.

O agente precisa interpretar eventos dentro de política.

Uma arquitetura segura separa:

FACT

de:

DECISION

e:

ACTION.

Assim:

EVENT
↓
OBSERVE
↓
VALIDATE
↓
DECIDE
↓
AUTHORIZE
↓
ACT

Essa separação reduz o risco de transformar qualquer mensagem numa ordem administrativa.

RACF agradece novamente.


🔐 CAPÍTULO 41 — MENSAGEM TAMBÉM PRECISA DE ZERO TRUST

Nosso agente não deveria confiar numa mensagem apenas porque ela apareceu numa fila.

Considere:

identity
authorization
queue permissions
message integrity
origin
schema validation
content validation

Uma mensagem malformada ou maliciosa pode tentar fazer o agente:

CALL TOOL
TRANSFER MONEY
DELETE DATA

Logo:

MQ

não elimina segurança.

Ele apenas transporta dados.

Autorização continua sendo outra camada.


🧾 CAPÍTULO 42 — SCHEMA É O COPYBOOK DA MENSAGEM

O programador COBOL conhece isso imediatamente.

Mensagem:

01 PAYMENT-MESSAGE.
   05 MSG-VERSION       PIC 9(04).
   05 PAYMENT-ID        PIC X(20).
   05 CUSTOMER-ID       PIC 9(09).
   05 AMOUNT            PIC S9(11)V99 COMP-3.
   05 EVENT-TIMESTAMP   PIC X(26).

Isso define estrutura.

Mas lembramos do Db2 dos Agentes:

ESTRUTURA NÃO É SEMÂNTICA.

Precisamos saber:

AMOUNT é em BRL?
PAYMENT-ID é único?
EVENT-TIMESTAMP usa qual timezone?
CUSTOMER-ID pode ser zero?
MSG-VERSION 0002 é compatível?

O copybook voltou.

Ele nunca foi embora.


🔄 CAPÍTULO 43 — VERSIONAMENTO DE MENSAGEM

Hoje:

VERSION 1

Amanhã precisamos adicionar:

CURRENCY.

Criamos:

VERSION 2.

Mas ainda existem consumidores antigos.

Agora precisamos pensar:

backward compatibility
forward compatibility
schema evolution

Nosso agente deve saber:

Consigo interpretar esta versão?

Se não:

QUARANTINE

é melhor do que:

VOU CHUTAR.

Especialmente quando “chutar” movimenta dinheiro.


🌊 CAPÍTULO 44 — A FILA É UM AMORTECEDOR, NÃO UM MILAGRE

Turing desenha:

PRODUCER
████████████████████████
          ↓
       QUEUE
~~~~~~~~~~~~~~~~~~~~~~~~
          ↓
CONSUMER
██████████

A fila absorve diferença temporária.

Mas se producer permanece mais rápido:

QUEUE DEPTH ↑

até algum limite operacional.

Portanto monitoramos:

depth
oldest age
put rate
get rate
consumer count
failure rate
backout count

Uma fila crescente é uma mensagem.

Ironicamente:

A própria fila está tentando falar com você.


🏁 CAPÍTULO 45 — A REGRA DE OURO

Alan Turing escreve no quadro:

MESSAGE RECEIVED
≠
BUSINESS ACTION COMPLETED

Depois:

BUSINESS ACTION COMPLETED
≠
MESSAGE ACKNOWLEDGED

Depois:

MESSAGE ACKNOWLEDGED
≠
WORLD STILL UNCHANGED

O pequeno robô fica olhando.

— Então eu não posso confiar em nada?

Turing sorri.

— Pode.

— Em quê?

— Em protocolos, transações, IDs, versões, políticas, observabilidade e verificações.

— Parece trabalhoso.

— É.

— E se eu simplesmente confiar que tudo dará certo?

Do fundo do CPD, cinco administradores começam a rir.


☕ EPÍLOGO — RECEBIDO NÃO SIGNIFICA TERMINADO

07:02.

A equipe da manhã chega.

Nosso agente recebe:

MESSAGE-ID..... M004821
CORREL-ID...... C009912
EVENT.......... PAYMENT_REQUESTED
PAYMENT-ID..... P88271
AMOUNT......... 850.00
SEQUENCE....... 42
EVENT-TIME..... 07:02:01

Ele verifica:

SCHEMA......... OK
VERSION........ SUPPORTED
AUTHORITY...... OK
DUPLICATE...... NO
ORDER.......... OK
FRESHNESS...... OK

Consulta Db2.

CURRENT STATE.. VALID

Inicia unidade de trabalho.

PROCESS PAYMENT
INSERT AUDIT
REGISTER MESSAGE

Confirma.

COMMIT.

Resultado:

SUCCESS.

Alguns milissegundos depois:

💥

O worker cai.

Reinicia.

A mensagem aparece novamente.

O velho agente teria gritado:

Já fiz isso!

O novo apenas consulta:

IDEMPOTENCY-KEY = P88271.

Resposta:

ALREADY PROCESSED.

Nenhum pagamento duplicado.

Nenhuma madrugada destruída.

Nenhum DBA perseguindo robôs pelo corredor.

O agente registra:

DUPLICATE DELIVERY
BUSINESS EFFECT SKIPPED
STATUS = SAFE

Turing toma o primeiro café da manhã.

O programador pergunta:

— Então a duplicata deixou de ser um problema?

— Não.

— Mas não aconteceu nada.

— Exatamente.

O programador pensa.

Turing continua:

— Engenharia confiável não é construir um universo onde falhas nunca acontecem.

Aponta para a tela:

REDELIVERY DETECTED

— É construir um sistema no qual falhas esperadas deixam de virar desastres inesperados.

O pequeno robô levanta a mão.

— Professor?

— Sim?

— Posso apagar a mensagem de 1999?

Do outro lado do CPD o administrador MQ grita:

— NÃO! PRIMEIRO FAZ BACKUP!

😂

Turing fecha o terminal.

Na tela permanece:

MQ
────────────────────────

MESSAGE-ID...... M004821
DELIVERY........ 2
PROCESSING...... IDEMPOTENT
BUSINESS EFFECT. ONCE
STATUS.......... SAFE

COMMIT.......... OK

E embaixo:

A MENSAGEM PODE CHEGAR NOVAMENTE.

O EFEITO NÃO PRECISA ACONTECER NOVAMENTE.

Essa é talvez a grande lição do MQ dos Agentes.

Porque quando centenas de inteligências artificiais começarem a conversar entre si, delegando tarefas, publicando eventos, recebendo respostas, reiniciando workers, atravessando APIs, bancos, filas e nuvens, não bastará perguntar:

A mensagem chegou?

Teremos de perguntar:

Qual mensagem?

De quem?

Quando?

Em qual ordem?

Quantas vezes?

Ainda é válida?

Já foi processada?

O efeito foi confirmado?

Posso executar novamente?

E se eu cair exatamente agora?

O mainframe conhece essa paranoia há décadas.

E talvez por isso tenha tanta coisa para ensinar aos agentes.

MQGET
   ↓
VALIDATE
   ↓
DEDUPLICATE
   ↓
REVALIDATE
   ↓
PROCESS
   ↓
COMMIT
   ↓
ACKNOWLEDGE

Alan Turing olha para o fluxo.

Toma mais um gole.

E acrescenta apenas uma linha:

IF IN DOUBT
   DO NOT CHARGE THE CUSTOMER TWICE.

READY

Vagner Renato Bellacosa, IBM Champion e especialista em IBM Mainframe
IBM Z17 SYSTEM ONLINE
Sobre o autor

Vagner Renato Bellacosa

IBM Champion 2026 • Especialista em IBM Mainframe

Vagner Renato Bellacosa trabalha com IBM Mainframe desde 1988 , é IBM Champion e especialista em COBOL, CICS, Db2, z/OS e IBM Z. Compartilha experiências profissionais, conhecimento técnico, história da computação e práticas do universo mainframe para aproximar novas gerações das tecnologias que sustentam empresas, bancos e governos ao redor do mundo.

IBM Champion IBM Z COBOL CICS Db2 z/OS Mainframe desde 1988
GitHub LinkedIn
Inicializando conteúdo...