Il problema che mi ha fatto impazzire per 2 anni

Lavoro con pipeline event-driven da quando EventBridge si chiamava ancora CloudWatch Events. E per 2 anni ho avuto un problema ricorrente: il limite dei 256KB.

Ogni volta che dovevo passare un payload grande (risposta LLM, evento CDC completo, log dettagliato), dovevo inventarmi qualcosa:

  • Pattern claim-check (salva su S3, passa il reference)
  • Split dell’evento su più messaggi
  • Bypass completo di EventBridge con Kinesis

Tutte soluzioni che funzionano, ma aggiungono latenza, complessità e altri pezzi da mantenere.

Poi il 29 gennaio 2026 AWS annuncia: EventBridge supporta 1MB payload. 4x il limite precedente.

Mi sono detto: “Ok, testiamo se è hype o se risolve davvero i miei problemi”.

Il progetto pilota: migrazione di una pipeline reale

Ho preso una pipeline di produzione che gestisce eventi da un’applicazione e-commerce:

  • Volume: ~500K eventi/giorno
  • Dimensione media: 400KB (sì, sopra il vecchio limite di 256KB)
  • Architettura precedente: Kinesis Data Streams → Lambda → Processing
  • Costo: ~$1.200/mese

Obiettivo: migrare a EventBridge 1MB, semplificare l’architettura, ridurre costi.

Prima vs Dopo: l’architettura che ho implementato

Prima (con Kinesis)

# Producer
kinesis.put_record(
    StreamName='orders-stream',
    Data=json.dumps(event),  # 400KB
    PartitionKey='order-123'
)

# Lambda consumer
def lambda_handler(event, context):
    record = json.loads(event['Records'][0]['kinesis']['data'])
    # Processing...

Problemi:

  • Gestione shard (hot shards, resharding)
  • Monitoring complesso
  • Costo shard-hour anche di notte

Dopo (con EventBridge 1MB)

# Producer (molto più semplice)
eventbridge.put_events(
    Entries=[{
        'Source': 'orders.service',
        'DetailType': 'OrderCreated',
        'Detail': json.dumps(event)  # 400KB, finalmente possibile!
    }]
)

# Lambda consumer (identico)
def lambda_handler(event, context):
    detail = json.loads(event['detail'])
    # Processing...

Vantaggi:

  • Zero gestione infrastruttura
  • Scale-to-zero (non pago se non uso)
  • Routing built-in

I numeri del risparmio (reali, non teorici)

Ho tenuto traccia per 30 giorni:

MetricaKinesis (prima)EventBridge (dopo)Delta
Costo mensile$1.184$387-$797
Eventi/giorno500K500K=
Latenza media45ms38ms-7ms
Ops overheadAltoZero-100%

$800 al mese di risparmio. Su una singola pipeline. Se ho 10 pipeline simili, parliamo di $8.000/mese.

Ma attenzione: non è sempre così.

Quando EventBridge 1MB batte Kinesis (e quando no)

✅ Usa EventBridge quando:

  • Throughput moderato (< 10K eventi/secondo)
  • Payload fino a 1MB (ovvio)
  • Multipli consumer con routing diverso
  • Non ti serve replay dei messaggi
  • Vuoi semplicità (zero shard management)

❌ Usa Kinesis quando:

  • Throughput altissimo (> 10K eventi/sec)
  • Ordinamento rigoroso richiesto
  • Replay necessario (riprocessare vecchi messaggi)
  • Processing real-time con latenza < 10ms

La mia regola empirica: se puoi permetterti 30-50ms di latenza e non hai bisogno di replay, EventBridge è probabilmente la scelta giusta.

Gli errori che ho fatto durante la migrazione

Errore 1: Non ho controllato la dimensione dei payload prima

Ho assunto che tutti i miei eventi fossero < 1MB. Errore. Alcuni eventi con immagini base64 superavano il mega.

Soluzione: Ho implementato un check automatico:

if len(json.dumps(event)) > 1_000_000:
    # Salva su S3, passa reference
    upload_to_s3(event)
    event = {'s3_reference': 's3://bucket/key'}

Errore 2: Ho dimenticato di aggiornare i timeout delle Lambda

Le mie Lambda erano configurate con 30s timeout. Con payload più grandi, alcune esecuzioni andavano in timeout.

Soluzione: Aumentato a 5 minuti per i consumer che processano payload grandi.

Errore 3: Non ho compresso i payload testuali

JSON si comprime bene (60-80% di riduzione). Invece di mandare 800KB di JSON, ne mando 200KB compressi.

import gzip
import base64

def compress_event(data):
    json_str = json.dumps(data)
    compressed = gzip.compress(json_str.encode('utf-8'))
    return base64.b64encode(compressed).decode('utf-8')

Pattern che finalmente funzionano senza workaround

1. Routing diretto LLM

Prima: LLM response → S3 → reference in EventBridge → Lambda → fetch S3 Dopo: LLM response → EventBridge diretto → Lambda

Risparmio: ~200ms di latenza per ogni chiamata.

2. CDC completo

Prima: Solo ID del record modificato in EventBridge, poi query al DB per dettagli Dopo: Stato before/after completo in EventBridge

Vantaggio: Zero query aggiuntive, consistenza garantita.

3. Log aggregation

Prima: Batch di log ogni 5 minuti per non superare il limite Dopo: Log in tempo reale con contesto completo

Vantaggio: Debugging immediato.

Il codice che uso in produzione ora

Ecco il mio publisher “intelligente” che gestisce automaticamente la dimensione:

import boto3
import json
import gzip
import base64

class SmartEventPublisher:
    def __init__(self):
        self.eventbridge = boto3.client('events')
        self.s3 = boto3.client('s3')
        self.bucket = 'my-events-bucket'
    
    def publish(self, event_data, detail_type, source):
        payload = json.dumps(event_data)
        size = len(payload.encode('utf-8'))
        
        # Se > 1MB, comprimi o usa S3
        if size > 800_000:  # Lascio margine
            compressed = self._compress(payload)
            if len(compressed) < 1_000_000:
                event_data = {'compressed_data': compressed}
            else:
                # Ancora troppo grande, usa S3
                key = f"events/{source}/{detail_type}/{uuid.uuid4()}.json"
                self.s3.put_object(Bucket=self.bucket, Key=key, Body=payload)
                event_data = {'s3_location': f's3://{self.bucket}/{key}'}
        
        # Pubblica su EventBridge
        return self.eventbridge.put_events(
            Entries=[{
                'Source': source,
                'DetailType': detail_type,
                'Detail': json.dumps(event_data)
            }]
        )
    
    def _compress(self, payload):
        compressed = gzip.compress(payload.encode('utf-8'))
        return base64.b64encode(compressed).decode('utf-8')

Conclusione: ne vale la pena?

Dopo 30 giorni di utilizzo in produzione, la risposta è sì, ma con cautela.

Vale la pena se:

  • Hai payload > 256KB ma < 1MB
  • Vuoi semplificare l’architettura
  • Risparmiare sui costi operativi
  • Non hai bisogno di replay o ordinamento rigoroso

Non vale la pena se:

  • Hai throughput estremo (>10K/sec)
  • Hai payload > 1MB regolarmente
  • Hai bisogno di replay
  • Ogni millisecondo conta

Per me, su 8 pipeline su 10, EventBridge 1MB è diventato la scelta default. Per le 2 pipeline high-throughput, rimango su Kinesis.

Voi avete provato il nuovo limite 1MB? Avete avuto problemi o tutto smooth? Raccontate nei commenti!


Disclaimer: Questi sono i risultati della mia esperienza personale. I tuoi numeri possono variare. Testa sempre prima in staging.


Configurazione completa: Trovate il codice su GitHub con Terraform e Python examples.

Post correlati: