El fan-out de 07-02 funciona, però té un sostre que ja es nota. mercadofresco-pedido-confirmado
transporta un únic tipus de fet; per a PedidoCancelado, StockBajo i RepartoAsignado caldria un
tema per a cadascun, cadascun amb les seves subscripcions, les seves polítiques de cua i els seus
filtres. Quatre temes avui, dotze l'any vinent, i un mapa de subscripcions que ningú no sap dibuixar
sencer. A més hi ha fets que interessen i que la botiga no publica —que una instància del grup
asg-mercadofresco-tienda canviï d'estat, que Trusted Advisor detecti un recurs ociós, que un
desplegament falli— i hi ha una ferida oberta: quan la cua d'analítica va estar mal configurada, els
esdeveniments d'aquelles hores es van perdre per sempre.
Amazon EventBridge és el bus d'esdeveniments sense servidor d'AWS. En lloc d'un canal per tipus de fet, hi ha un bus on tot es publica, i regles que decideixen on va cada esdeveniment mirant-ne el contingut complet. L'emissor no coneix ningú; el receptor no depèn de l'emissor; el que els uneix és un patró JSON que es pot canviar sense desplegar codi. I de regal, EventBridge rep de fàbrica els esdeveniments de més de 200 serveis d'AWS i pot arxivar i reproduir tot el que hi passa.
En aquesta lliçó el Luis crea bus-mercadofresco, dissenya el catàleg d'esdeveniments de negoci de la
botiga, escriu patrons de complexitat creixent, connecta una destinació d'API cap a l'ERP del magatzem,
programa la càrrega nocturna a Redshift amb cron, i per fi explota els Streams de mercadofresco-carritos
que van quedar presentats i sense fer servir a 06-02.
Avís de cost. EventBridge cobra 1,00 USD per milió d'esdeveniments personalitzats publicats; els esdeveniments de serveis d'AWS al bus per defecte són gratuïts. L'arxiu costa per GB emmagatzemat i la reproducció es cobra com una publicació nova: reproduir un mes d'esdeveniments torna a passar per caixa. Pipes i Scheduler tenen la seva pròpia tarifa. Al final tens la neteja. Dades fictícies.
Contingut
- SNS o EventBridge: la comparació honesta
- Busos: per defecte, personalitzat i de socis
- Anatomia d'un esdeveniment
- El catàleg d'esdeveniments de MercadoFresco
- Regles i patrons d'esdeveniment
- Destinacions i transformació de l'entrada
- Reintents, edat màxima de l'esdeveniment i DLQ per destinació
- Esdeveniments dels serveis d'AWS
- Regles programades i EventBridge Scheduler
- Registre d'esquemes i enllaços de codi
- Arxiu i reproducció d'esdeveniments
- EventBridge Pipes i els Streams de
mercadofresco-carritos - Arquitectura dirigida per esdeveniments: contractes i versionatge
- Observabilitat i cost
- Errors habituals i consells
- Exercicis
- Conclusió
SNS o EventBridge: la comparació honesta
Tots dos lliuren un missatge a diverses destinacions. La diferència està en què saben del contingut i en què porten posat de fàbrica.
| Amazon SNS | Amazon EventBridge | |
|---|---|---|
| Unitat | Tema per tipus de missatge | Un bus per a molts tipus |
| Filtratge | Atributs o cos, regles senzilles | Patró sobre tot l'esdeveniment, imbricat, arrays |
| Destinacions per regla/subscripció | 1 | Fins a 5 |
| Orígens d'AWS | Només els que publiquen explícitament | 200+ serveis de fàbrica |
| Orígens SaaS | No | Busos de socis (Datadog, Shopify, Zendesk…) |
| Esquemes | No | Registre i descobriment automàtic |
| Arxiu i reproducció | No | Sí |
| Transformació de l'entrada | No | Sí (input transformer) |
| Latència típica | Desenes de ms | Centenars de ms (~0,5 s) |
| Rendiment | Molt alt (>100.000/s) | 10.000 publicacions/s per defecte (ampliable) |
| Cost per milió | 0,50 USD publicar + lliuraments | 1,00 USD publicar, lliuraments inclosos |
| Correu, SMS, push | Sí | No |
El criteri pràctic. Fes servir SNS quan el patró sigui fan-out pur d'un fet a moltes destinacions amb filtres simples, quan importi la latència mínima, quan el volum sigui molt alt o quan la destinació sigui una persona (correu, SMS). Fes servir EventBridge quan hi hagi diversos tipus d'esdeveniment sobre un mateix canal, quan l'encaminament depengui del contingut, quan vulguis reaccionar a esdeveniments d'AWS o d'un SaaS, quan necessitis arxiu i reproducció, o quan la destinació sigui una API externa.
MercadoFresco acaba fent servir tots dos, i no és cap contradicció: bus-mercadofresco per als
esdeveniments de negoci i per a tot el que vingui d'AWS, i SNS per al fan-out d'alt volum de
mercadofresco-pedido-confirmado —que ja funciona i té menys latència— i per als avisos a persones
d'alertas-mercadofresco. De fet, un tema d'SNS pot ser destinació d'una regla d'EventBridge, cosa
que permet combinar-los sense duplicar res.
Busos: per defecte, personalitzat i de socis
Un bus d'esdeveniments és un canal amb nom. N'hi ha tres classes:
- Bus per defecte (
default). Existeix a cada regió sense crear-lo. Aquí arriben automàticament els esdeveniments dels serveis d'AWS del compte: canvis d'estat d'EC2, resultats de Trusted Advisor, transicions de tasques d'ECS, fallades de desplegament. També accepta esdeveniments propis, però barrejar-los amb el soroll d'AWS complica les regles i l'arxiu. - Bus personalitzat. El que crea la teva aplicació per als seus esdeveniments de negoci. Permet polítiques d'accés pròpies, arxiu propi i límits propis.
- Bus de soci (partner event bus). El crea un SaaS associat per enviar-te els seus esdeveniments sense que muntis webhooks: la passarel·la de pagament, l'ERP al núvol o l'eina de suport.
export PERFIL="--profile mercadofresco-dev --region eu-west-1"
aws events create-event-bus --name bus-mercadofresco \
--tags Key=Proyecto,Value=mercadofresco Key=Entorno,Value=produccion \
Key=Componente,Value=integracion Key=Propietario,Value=marta \
Key=CentroCoste,Value=tecnologia $PERFILMercadoFresco separa clarament: bus-mercadofresco per als esdeveniments que publica l'aplicació, i el
bus default per reaccionar al que fa AWS.
Anatomia d'un esdeveniment
Tot esdeveniment d'EventBridge té el mateix sobre. Els camps que controles tu són quatre; la resta els posa el servei.
{
"version": "0",
"id": "3f8a1c22-9e7d-4b10-a5f1-6c2b0e4d7a19",
"detail-type": "PedidoConfirmado",
"source": "mercadofresco.tienda",
"account": "111122223333",
"time": "2026-08-02T18:41:07Z",
"region": "eu-west-1",
"resources": ["arn:aws:rds:eu-west-1:111122223333:cluster:aurora-mercadofresco-pedidos"],
"detail": {
"version": 1,
"pedido_id": "PED-2026-084417",
"cliente_id": "CLI-30912",
"importe_eur": 48.20,
"franja_entrega": "24h",
"provincia": "Barcelona",
"lineas": [
{ "sku": "FRUT-FRES-011", "unidades": 2, "precio_eur": 3.10 },
{ "sku": "PESC-FRES-002", "unidades": 1, "precio_eur": 12.40 }
],
"confirmado_en": "2026-08-02T18:41:07Z"
}
}| Camp | Qui el posa | Per a què serveix |
|---|---|---|
source |
Tu | Espai de noms de l'emissor. Convenció: <empresa>.<domini> |
detail-type |
Tu | Què ha passat. És el camp que més es fa servir per encaminar |
detail |
Tu | La càrrega útil, JSON lliure |
resources |
Tu | ARN dels recursos implicats; permet filtrar per recurs |
id, time, region, account |
EventBridge | Metadades; time serveix per a l'arxiu i la reproducció |
Dos advertiments sobre el detail. Primer: l'esdeveniment complet no pot passar de 256 KB, igual que
un missatge d'SQS; si el detall és gran, desa a S3 i envia la referència. Segon: detail és un contracte
amb tercers, no una estructura interna. Hi tornarem al final de la lliçó.
El catàleg d'esdeveniments de MercadoFresco
Abans d'escriure una sola regla, la Marta i el Luis escriuen el catàleg. És un document d'una pàgina, i és la peça de govern més rendible de tot el mòdul.
source |
detail-type |
Quan s'emet | Camps clau del detail |
|---|---|---|---|
mercadofresco.tienda |
PedidoConfirmado |
Cobrament correcte i comanda escrita a Aurora | pedido_id, cliente_id, importe_eur, franja_entrega, provincia, lineas |
mercadofresco.tienda |
PedidoCancelado |
El client o el sistema anul·len una comanda | pedido_id, motivo, importe_devuelto_eur |
mercadofresco.almacen |
StockBajo |
Un SKU baixa del llindar de reposició | sku, unidades_restantes, umbral, proveedor_id |
mercadofresco.reparto |
RepartoAsignado |
S'assigna repartidor i franja | pedido_id, repartidor_id, franja, eta |
Tres convencions que estalvien molt de dolor. El detail-type va en passat i descriu un fet, no una
ordre: PedidoConfirmado, no ConfirmarPedido; si descriu una ordre, has tornat a l'acoblament que
volies evitar. El source identifica el domini emissor, no l'equip ni el servei tècnic, perquè
sobrevisqui a reorganitzacions. I el detail porta sempre version, que és l'única cosa que
permetrà fer evolucionar el contracte sense trencar consumidors.
Publicar és una crida:
import json, boto3
from datetime import datetime, timezone
eb = boto3.client("events", region_name="eu-west-1")
def publicar_comanda_confirmada(comanda):
resposta = eb.put_events(Entries=[{
"EventBusName": "bus-mercadofresco",
"Source": "mercadofresco.tienda",
"DetailType": "PedidoConfirmado",
"Time": datetime.now(timezone.utc),
"Resources": ["arn:aws:rds:eu-west-1:111122223333:cluster:aurora-mercadofresco-pedidos"],
"Detail": json.dumps({"version": 1, **comanda}, ensure_ascii=False),
}])
# put_events retorna 200 encara que falli alguna entrada: cal mirar FailedEntryCount.
if resposta["FailedEntryCount"]:
for e in resposta["Entries"]:
if "ErrorCode" in e:
log.error("esdeveniment no publicat",
extra={"code": e["ErrorCode"], "msg": e["ErrorMessage"]})
return respostaput_events accepta fins a 10 entrades per crida i té el mateix parany que send_message_batch de
07-01: 200 amb fallades parcials a dins. Si no comproves FailedEntryCount, perds esdeveniments en
silenci.
Regles i patrons d'esdeveniment
Una regla té un patró i fins a cinc destinacions. Un patró d'esdeveniment és un JSON amb la mateixa forma que l'esdeveniment, on cada valor és una llista d'alternatives. L'esdeveniment hi encaixa si tots els camps del patró coincideixen.
El patró més simple: totes les comandes confirmades.
A partir d'aquí, el llenguatge creix. Aquests són els operadors, aplicats al detall de la comanda:
| Operador | Patró | Què selecciona |
|---|---|---|
| Coincidència exacta | {"detail":{"franja_entrega":["24h"]}} |
Franja urgent |
| Llista (OR) | {"detail":{"provincia":["Barcelona","Girona"]}} |
Qualsevol de les dues |
prefix |
{"detail-type":[{"prefix":"Pedido"}]} |
PedidoConfirmado i PedidoCancelado |
suffix |
{"detail":{"lineas":{"sku":[{"suffix":"-BIO"}]}}} |
Alguna línia ecològica |
anything-but |
{"detail":{"provincia":[{"anything-but":["Baleares","Canarias"]}]}} |
Tot menys les illes |
numeric |
{"detail":{"importe_eur":[{"numeric":[">=",150]}]}} |
Comandes grans |
| Rang | {"detail":{"importe_eur":[{"numeric":[">",50,"<=",200]}]}} |
Entre 50 i 200 € |
exists |
{"detail":{"cupon":[{"exists":true}]}} |
Només amb cupó |
cidr |
{"detail":{"ip":[{"cidr":"10.0.0.0/16"}]}} |
Origen intern |
equals-ignore-case |
{"detail":{"provincia":[{"equals-ignore-case":"barcelona"}]}} |
Sense importar majúscules |
$or |
Vegeu a sota | OR entre camps diferents |
Les regles de composició són les mateixes que a SNS i continuen sent la font número u de patrons que no encaixen: dins d'un camp, la llista és OR; entre camps diferents, AND. Aquest patró exigeix les dues coses alhora:
{
"source": ["mercadofresco.tienda"],
"detail-type": ["PedidoConfirmado"],
"detail": {
"franja_entrega": ["24h"],
"importe_eur": [{ "numeric": [">=", 60] }]
}
}I aquest selecciona urgents o grans, que és diferent:
{
"source": ["mercadofresco.tienda"],
"detail-type": ["PedidoConfirmado"],
"$or": [
{ "detail": { "franja_entrega": ["24h"] } },
{ "detail": { "importe_eur": [{ "numeric": [">=", 60] }] } }
]
}Els arrays tenen una semàntica pròpia que cal entendre. El patró
{"detail":{"lineas":{"sku":[{"prefix":"PESC-"}]}}} encaixa si alguna de les línies comença per
PESC-. No hi ha manera d'exigir que totes ho facin: EventBridge avalua els arrays amb semàntica
existencial. Si necessites «totes», el filtre va a la destinació, no a la regla.
Crear la regla i enganxar-hi destinacions:
aws events put-rule --name regla-mf-pedido-confirmado-almacen \
--event-bus-name bus-mercadofresco --state ENABLED \
--description "Encamina comandes confirmades cap a la cua del magatzem" \
--event-pattern '{"source":["mercadofresco.tienda"],"detail-type":["PedidoConfirmado"]}' $PERFIL
aws events put-targets --rule regla-mf-pedido-confirmado-almacen \
--event-bus-name bus-mercadofresco \
--targets '[{
"Id": "cola-almacen",
"Arn": "arn:aws:sqs:eu-west-1:111122223333:cola-mercadofresco-almacen",
"DeadLetterConfig": {"Arn":"arn:aws:sqs:eu-west-1:111122223333:mercadofresco-eventbridge-fallidas"},
"RetryPolicy": {"MaximumRetryAttempts": 8, "MaximumEventAgeInSeconds": 3600}
}]' $PERFILProvar un patró sense publicar res és possible i convé fer-ho sempre:
aws events test-event-pattern \
--event-pattern file://patron.json \
--event file://evento-ejemplo.json $PERFIL
# → { "Result": true }Destinacions i transformació de l'entrada
Una regla admet fins a cinc destinacions, de més de 20 tipus. Les que fa servir MercadoFresco:
| Destinació | Ús | Nota |
|---|---|---|
| Cua SQS | Feina asíncrona duradora | La més habitual; permet MessageGroupId en FIFO |
| Funció Lambda | Reacció immediata | EventBridge gestiona el permís lambda:InvokeFunction |
| Tema SNS | Reaprofitar el fan-out ja muntat | Uneix els dos mons |
| Màquina d'estats | Arrencar el procés de comanda | Ho veurem a 07-04 |
| Destinació d'API | Cridar l'ERP del soci per HTTPS | Amb autenticació i contrapressió gestionades |
| Un altre bus / un altre compte | Federar entorns | Requereix política de bus a la destinació |
| Firehose, Kinesis, Log group | Bolcat i auditoria | A mercadofresco-registros-web |
La destinació d'API mereix atenció perquè resol un problema real. Cridar una API externa des d'una Lambda obliga a gestionar credencials, reintents i límits de ritme a mà. Una destinació d'API ho fa EventBridge: desa les credencials en una connexió (que al seu torn les diposita a Secrets Manager), afegeix la capçalera d'autenticació i limita les invocacions per segon.
aws events create-connection --name conexion-erp-almacen \
--authorization-type API_KEY \
--auth-parameters '{"ApiKeyAuthParameters":{"ApiKeyName":"x-api-key","ApiKeyValue":"FICTICIA-123"}}' \
$PERFIL
aws events create-api-destination --name destino-api-erp-almacen \
--connection-arn arn:aws:events:eu-west-1:111122223333:connection/conexion-erp-almacen/abc123 \
--invocation-endpoint https://erp.socio.example/v1/pedidos \
--http-method POST \
--invocation-rate-limit-per-second 12 $PERFIL--invocation-rate-limit-per-second 12 és exactament el límit que l'ERP aguanta. EventBridge no el
supera encara que arribin 900 esdeveniments de cop, i la resta espera amb reintents.
La transformació de l'entrada (input transformer) evita l'acoblament entre el format de l'esdeveniment i el que la destinació espera. Sense ella, l'ERP hauria d'entendre el sobre complet d'EventBridge i el nom exacte dels nostres camps, i qualsevol canvi a l'esdeveniment trencaria el soci.
{
"InputPathsMap": {
"pedido": "$.detail.pedido_id",
"cliente": "$.detail.cliente_id",
"franja": "$.detail.franja_entrega",
"momento": "$.time"
},
"InputTemplate": "{\"orderRef\":\"<pedido>\",\"customerRef\":\"<cliente>\",\"deliverySlot\":\"<franja>\",\"createdAt\":\"<momento>\",\"channel\":\"web\"}"
}InputPathsMap extreu valors amb JSONPath i els dona un àlies; InputTemplate compon la càrrega que rep
la destinació. El resultat és que l'ERP rep el seu propi vocabulari (orderRef, customerRef) sense que
MercadoFresco hagi de reanomenar res al seu esdeveniment. La traducció viu a la regla, que és el lloc
barat de canviar.
Reintents, edat màxima de l'esdeveniment i DLQ per destinació
Si una destinació falla, EventBridge reintenta amb retrocés exponencial durant 24 hores i fins a 185 intents per defecte. Tots dos límits s'ajusten per destinació, i el primer que es compleixi atura els intents:
MaximumRetryAttempts: nombre màxim de reintents (0–185).MaximumEventAgeInSeconds: antiguitat màxima de l'esdeveniment (60–86.400 s).
MaximumEventAgeInSeconds és el paràmetre que més s'oblida i el que més importa en negoci. Un avís de
repartiment lliurat 20 hores tard no val res: és preferible que caigui a la DLQ al cap d'una hora i que
algú se'l miri, en lloc que arribi quan el repartiment ja s'ha fet. La Marta el fixa en 3.600 s per a
tot el que té a veure amb comandes.
La DLQ per destinació (DeadLetterConfig) recull el que no s'ha pogut lliurar. És una cua SQS
normal, i el missatge que hi arriba inclou atributs amb el motiu: RULE_ARN, TARGET_ARN, ERROR_CODE,
ERROR_MESSAGE i EXHAUSTED_RETRY_CONDITION. Aquest últim camp és or pur per al diagnòstic: diu si es
van esgotar els reintents o si va vèncer l'edat màxima.
No confonguis les tres DLQ que ja conviuen a MercadoFresco:
| DLQ | Recull | Causa típica |
|---|---|---|
| De la cua SQS | El que el consumidor no va poder processar | Dades invàlides, dependència caiguda |
| De la subscripció SNS | El que SNS no va poder lliurar | Permisos, endpoint caigut |
| De la destinació d'EventBridge | El que EventBridge no va poder lliurar | Permisos, destinació saturada, edat vençuda |
Esdeveniments dels serveis d'AWS
Aquesta és la capacitat que SNS no té: més de 200 serveis d'AWS publiquen al bus default sense que
configuris res. Només cal escriure la regla.
Una instància del grup de la botiga que s'apaga o passa a estat degradat:
{
"source": ["aws.ec2"],
"detail-type": ["EC2 Instance State-change Notification"],
"detail": { "state": ["stopped", "terminated", "stopping"] }
}Una troballa de Trusted Advisor (05-05), que fins ara calia anar a mirar a mà:
{
"source": ["aws.trustedadvisor"],
"detail-type": ["Trusted Advisor Check Item Refresh Notification"],
"detail": { "status": ["WARN", "ERROR"] }
}Una tasca d'ECS que mor (mòdul 10) o un desplegament de CodeDeploy que falla (08-03):
{
"source": ["aws.ecs", "aws.codedeploy"],
"detail-type": [
"ECS Task State Change",
"CodeDeploy Deployment State-change Notification"
],
"detail": { "state": ["STOPPED"], "status": ["FAILURE"] }
}Compte amb aquest últim: en combinar dos orígens en una regla, el patró detail s'aplica a tots dos i
pot no encaixar amb cap. És més net una regla per origen, encara que sembli repetitiu: els patrons
queden llegibles i cadascuna pot tenir les seves pròpies destinacions i la seva pròpia DLQ.
MercadoFresco crea regla-mf-infra-incidentes amb destinació alertas-mercadofresco, i la
transformació de l'entrada converteix l'esdeveniment cru en una frase llegible per a la Marta:
{
"InputPathsMap": { "recurs": "$.detail.instance-id", "estat": "$.detail.state" },
"InputTemplate": "\"La instancia <recurs> ha passat a estat <estat> a eu-west-1.\""
}Aquest és un bon moment per assenyalar el canvi de mentalitat: l'operació passa de consultar a reaccionar. En lloc que algú revisi Trusted Advisor cada dilluns, un esdeveniment obre un tiquet quan hi ha alguna cosa per mirar.
Regles programades i EventBridge Scheduler
EventBridge també dispara per temps. Hi ha dos mecanismes i convé saber quin fer servir.
Les regles programades clàssiques viuen al bus default i fan servir schedule-expression:
aws events put-rule --name regla-mf-limpiar-carritos \
--schedule-expression "cron(0 3 * * ? *)" --state ENABLED \
--description "Neteja diaria de cistelles caducades a les 03:00 UTC" $PERFILEventBridge Scheduler és el servei dedicat, més nou i preferible per a gairebé tot: admet zones horàries amb horari d'estiu, finestres de dispersió (flexible time windows) per no llançar mil tasques al mateix segon, programacions d'un sol ús, i més de 270 destinacions amb els mateixos reintents i DLQ que les regles.
aws scheduler create-schedule-group --name grupo-mf-programado $PERFIL
aws scheduler create-schedule --name programador-mf-carga-nocturna \
--group-name grupo-mf-programado \
--schedule-expression "cron(30 2 * * ? *)" \
--schedule-expression-timezone "Europe/Madrid" \
--flexible-time-window '{"Mode":"FLEXIBLE","MaximumWindowInMinutes":15}' \
--target '{
"Arn": "arn:aws:lambda:eu-west-1:111122223333:function:mercadofresco-carga-redshift",
"RoleArn": "arn:aws:iam::111122223333:role/rol-mf-scheduler",
"Input": "{\"origen\":\"aurora\",\"destino\":\"analitica.hechos_pedidos\",\"modo\":\"incremental\"}",
"RetryPolicy": {"MaximumRetryAttempts": 3, "MaximumEventAgeInSeconds": 3600},
"DeadLetterConfig": {"Arn":"arn:aws:sqs:eu-west-1:111122223333:mercadofresco-eventbridge-fallidas"}
}' $PERFILEl --schedule-expression-timezone "Europe/Madrid" és la raó principal per preferir Scheduler: amb una
regla clàssica en UTC, la càrrega nocturna s'executaria a les 04:30 a l'hivern i a les 03:30 a l'estiu,
desalineada amb el tancament comptable. I MaximumWindowInMinutes: 15 reparteix l'arrencada per no
crear un pic de connexions contra aurora-mf-lector-2.
| Regla programada | EventBridge Scheduler | |
|---|---|---|
| Zona horària i horari d'estiu | No (només UTC) | Sí |
| Finestra flexible | No | Sí |
| Programació d'un sol ús | No | Sí (at(...)) |
| Límit per compte | 300 regles per bus | 1 milió de programacions |
| Destinacions | ~20 tipus | 270+ |
| Cost | Gratis | 1,00 USD/milió d'invocacions |
Les dues tasques nocturnes de MercadoFresco queden així: programador-mf-carga-nocturna a les 02:30
hora peninsular carrega les comandes del dia a analitica.hechos_pedidos de
wg-mercadofresco-analitica, i programador-mf-limpiar-carritos a les 03:00 recorre i consolida el que
el TTL de mercadofresco-carritos ja ha anat caducant. Compte: les expressions cron d'AWS tenen sis
camps (minut, hora, dia del mes, mes, dia de la setmana, any) i no admeten * a dia del mes i dia de
la setmana alhora —d'aquí el ?—.
Registre d'esquemes i enllaços de codi
El registre d'esquemes guarda l'estructura dels teus esdeveniments en format OpenAPI/JSON Schema. Amb el descobriment activat en un bus, EventBridge infereix l'esquema del que hi passa i el versiona automàticament.
aws schemas create-discoverer \
--source-arn arn:aws:events:eu-west-1:111122223333:event-bus/bus-mercadofresco $PERFIL
aws schemas list-schemas --registry-name discovered-schemas $PERFILD'un esquema es generen enllaços de codi (code bindings) per a Python, Java o TypeScript: classes
tipades que representen l'esdeveniment, de manera que el consumidor deixa de fer
evento["detail"]["pedido_id"] amb els dits creuats. En Python el valor afegit és menor que en Java,
però el registre continua sent útil per un altre motiu: és la documentació viva del catàleg. Quan
màrqueting pregunti quins camps porta PedidoConfirmado, la resposta és un esquema versionat, no un
missatge de xat. El descobriment costa uns 0,10 USD per milió d'esdeveniments processats, així que convé
tenir-lo actiu només mentre el catàleg evoluciona.
Arxiu i reproducció d'esdeveniments
Aquesta és la capacitat que hauria salvat l'incident de 07-02. Un arxiu desa còpia de tots els esdeveniments que passen per un bus —opcionalment filtrats per patró— durant el temps que decideixis.
aws events create-archive --archive-name archivo-mercadofresco-eventos \
--event-source-arn arn:aws:events:eu-west-1:111122223333:event-bus/bus-mercadofresco \
--retention-days 90 \
--event-pattern '{"source":[{"prefix":"mercadofresco."}]}' $PERFILI quan alguna cosa va malament, es reprodueix una finestra de temps cap a les regles afectades:
aws events start-replay --replay-name reproduccion-analitica-20260802 \
--event-source-arn arn:aws:events:eu-west-1:111122223333:archive/archivo-mercadofresco-eventos \
--event-start-time 2026-08-02T08:00:00Z \
--event-end-time 2026-08-02T14:00:00Z \
--destination '{
"Arn": "arn:aws:events:eu-west-1:111122223333:event-bus/bus-mercadofresco",
"FilterArns": ["arn:aws:events:eu-west-1:111122223333:rule/bus-mercadofresco/regla-mf-pedido-confirmado-analitica"]
}' $PERFILFilterArns és imprescindible i és el que separa una recuperació d'un desastre: sense ell, la
reproducció dispara totes les regles del bus, i tornaries a cobrar targetes, a enviar correus i a
avisar el magatzem de comandes de fa sis hores. Amb ell, només es reprocessa la regla d'analítica, que és
la que es va perdre els esdeveniments.
Tres coses més que cal saber abans de fer-ho servir de debò:
- Els esdeveniments reproduïts porten
replay-nameal sobre. Un consumidor els pot distingir i actuar en conseqüència —per exemple, no tornar a notificar ningú—. - L'ordre no es garanteix dins de la reproducció, i els esdeveniments arriben molt més de pressa que al seu moment original. El consumidor ha de ser idempotent i aguantar el ritme.
- Reproduir costa com publicar. Un mes d'esdeveniments reproduït són un mes d'esdeveniments facturats de nou, més l'emmagatzematge de l'arxiu (uns 0,10 USD per GB i mes).
L'arxiu també serveix per a una cosa menys dramàtica i molt útil: poblar un entorn de proves amb trànsit real, reproduint una tarda de divendres contra un bus de desenvolupament.
EventBridge Pipes i els Streams de mercadofresco-carritos
A 06-02 vam activar DynamoDB Streams a mercadofresco-carritos i ho vam deixar allà, presentat i sense
explotar. EventBridge Pipes és la peça que faltava: una canonada punt a punt entre un origen que se
sondeja i una destinació, amb dos passos opcionals al mig.
flowchart LR
ORIG[(DynamoDB Streams<br/>mercadofresco-carritos)] --> FIL[Filtratge<br/>nomes REMOVE per TTL]
FIL --> ENR[Enriquiment<br/>Lambda: afegeix dades del client]
ENR --> DEST{{bus-mercadofresco<br/>CarritoAbandonado}}
DEST --> R1[regla: avis a marqueting]
DEST --> R2[regla: cua d'analitica]
style FIL fill:#fff3cd
style ENR fill:#cfe2ff
Els orígens de Pipes són els que cal sondejar: DynamoDB Streams, Kinesis, SQS, Amazon MQ i Kafka. Les destinacions són qualsevol d'EventBridge. I els dos passos intermedis són la raó de la seva existència:
- Filtratge: descarta el que no interessa abans de pagar per processar-ho. El stream de cistelles
genera un registre per cada
UpdateItem—centenars de milers al dia—, però només interessen elsREMOVEprovocats pel TTL, que són les cistelles abandonades de debò. - Enriquiment: crida una Lambda, una API o una màquina d'estats per completar el registre abans de
lliurar-lo. El stream porta el
CLIENTE#<id>però no el correu ni el nom; l'enriquiment els busca a Aurora.
aws pipes create-pipe --name pipe-mf-carritos-abandonados \
--role-arn arn:aws:iam::111122223333:role/rol-mf-pipes \
--source arn:aws:dynamodb:eu-west-1:111122223333:table/mercadofresco-carritos/stream/2026-07-01T00:00:00.000 \
--source-parameters '{
"DynamoDBStreamParameters": {"StartingPosition":"LATEST","BatchSize":50,
"MaximumBatchingWindowInSeconds":30},
"FilterCriteria": {"Filters":[{"Pattern":"{\"eventName\":[\"REMOVE\"],\"userIdentity\":{\"principalId\":[\"dynamodb.amazonaws.com\"]}}"}]}
}' \
--enrichment arn:aws:lambda:eu-west-1:111122223333:function:mercadofresco-enriquecer-carrito \
--target arn:aws:events:eu-west-1:111122223333:event-bus/bus-mercadofresco \
--target-parameters '{"EventBridgeEventBusParameters":{"Source":"mercadofresco.carritos",
"DetailType":"CarritoAbandonado"}}' $PERFILEl filtre té un detall exquisit: userIdentity.principalId = dynamodb.amazonaws.com distingeix els
esborrats fets pel TTL dels que fa l'aplicació en confirmar una comanda. Sense aquesta condició,
màrqueting enviaria correus de «t'has deixat alguna cosa» a clients que acaben de comprar. És un exemple
perfecte de per què el filtratge ha d'estar a prop de l'origen i entendre el domini.
Amb això es tanca un fil que estava obert des del mòdul 6: els 55 GB de cistelles zombis que el TTL va començar a netejar ara, a més, generen un esdeveniment de negoci aprofitable.
Arquitectura dirigida per esdeveniments: contractes i versionatge
Els esdeveniments desacoblen, però no de franc. Hi ha tres veritats que convé acceptar aviat.
Un esdeveniment és una API pública. Tan bon punt el publiques en un bus compartit, no saps qui el consumeix: aquest és l'objectiu. I llavors no el pots canviar al teu gust. Treure un camp, reanomenar-lo o canviar-ne el tipus trenca consumidors que ni tan sols saps que existeixen, i ho descobriràs en producció.
Les regles d'evolució compatible són curtes: es poden afegir camps opcionals; no es pot
treure ni reanomenar un camp, ni canviar-ne el tipus, ni canviar el significat d'un valor existent, ni
endurir una restricció. Quan calgui un canvi incompatible, es publica una versió nova en paral·lel
—"version": 2 al detall, o un detail-type nou PedidoConfirmadoV2— i es mantenen totes dues fins que
els consumidors migrin. Per això version va al detall des del primer esdeveniment: sense ell, la
migració no té per on començar.
L'acoblament no desapareix, es desplaça. Abans la botiga depenia de l'ERP; ara tothom depèn del
format de l'esdeveniment. És un canvi molt favorable —el contracte és explícit, versionable i
verificable amb test-event-pattern— però continua sent una dependència. La disciplina que el manté sa
és la del catàleg: res no es publica a bus-mercadofresco sense ser a la taula, i res no es canvia
sense pujar la versió.
Un últim advertiment sobre el disseny: els esdeveniments descriuen fets, les ordres manen accions. Si
el teu esdeveniment es diu EnviarCorreoConfirmacion, has posat una ordre en un bus, i l'emissor torna a
saber què ha de passar després. L'esdeveniment correcte és PedidoConfirmado; que això impliqui un
correu és decisió del consumidor.
Observabilitat i cost
| Mètrica | Què indica | Acció |
|---|---|---|
TriggeredRules |
Regles que hi van encaixar | Si és 0, el patró no coincideix |
MatchedEvents |
Esdeveniments que van encaixar amb alguna regla | Comparar amb el publicat |
FailedInvocations |
La destinació va rebutjar la invocació | Alarma: gairebé sempre permisos |
InvocationsFailedToBeSentToDlq |
Ni tan sols es va poder escriure a la DLQ | Alarma crítica |
ThrottledRules |
S'ha superat el límit d'invocacions | Demanar augment de quota |
PutEventsFailedEntriesCount |
Entrades rebutjades en publicar | Revisar el publicador |
La combinació més útil per depurar és MatchedEvents = 0 amb publicacions no nul·les: significa que cap
patró no hi encaixa, i gairebé sempre és un source mal escrit o un detail-type amb una majúscula de
diferència —els patrons distingeixen majúscules—.
A més, EventBridge s'integra amb CloudWatch Logs com a destinació: una regla amb patró ampli i com a destinació un grup de registres permet veure tot el que passa pel bus durant una investigació. És car deixar-ho permanentment, però és l'eina més ràpida quan alguna cosa no apareix on hauria.
| Concepte | Preu | MercadoFresco |
|---|---|---|
| Esdeveniments personalitzats publicats | 1,00 USD/milió | 480.000/mes → 0,48 USD |
| Esdeveniments de serveis d'AWS | Gratis | ~90.000/mes → 0 USD |
| Regles i destinacions | Gratis | — |
| Arxiu (emmagatzematge) | ~0,10 USD/GB-mes | 3,4 GB × 90 dies → 0,34 USD |
| Reproducció | 1,00 USD/milió | Només en incidents |
| Descobriment d'esquemes | ~0,10 USD/milió | 0,05 USD |
| Pipes | ~0,40 USD/milió de peticions | 210.000 després de filtrar → 0,08 USD |
| Scheduler | 1,00 USD/milió | 60/mes → 0 USD |
| Total | ~0,95 USD/mes |
Els esdeveniments no filtrats són el que pot disparar la factura: si el pipe de cistelles no filtrés els
MODIFY, processaria 5,4 milions de registres al mes en lloc de 210.000. Filtrar a l'origen no és
només higiene de disseny; és la partida principal.
aws events remove-targets --rule regla-mf-pedido-confirmado-almacen \
--event-bus-name bus-mercadofresco --ids cola-almacen $PERFIL
aws events delete-rule --name regla-mf-pedido-confirmado-almacen \
--event-bus-name bus-mercadofresco $PERFIL
aws pipes delete-pipe --name pipe-mf-carritos-abandonados $PERFIL
aws scheduler delete-schedule --name programador-mf-carga-nocturna \
--group-name grupo-mf-programado $PERFIL
aws events delete-archive --archive-name archivo-mercadofresco-eventos $PERFIL
aws events delete-event-bus --name bus-mercadofresco $PERFILUn bus no es pot esborrar si té regles amb destinacions: cal treure destinacions, després regles, després
el bus. És la causa habitual de ResourceInUseException als scripts de neteja.
Errors Habituals i Consells
Patró que no encaixa per majúscules o per un source mal escrit. MatchedEvents a 0 sense cap
error. Fes servir test-event-pattern abans de desplegar; t'estalvia hores. I no confonguis OR i
AND: dins d'un camp, llista = OR; entre camps, AND; per a OR entre camps, $or.
Esperar que un patró sobre un array exigeixi «tots». EventBridge avalua els arrays amb semàntica existencial: encaixa si algun dels elements ho compleix.
No comprovar FailedEntryCount a put_events. Retorna 200 amb fallades parcials, igual que
send_message_batch. Esdeveniments perduts en silenci.
Publicar els esdeveniments de negoci al bus default. Es barregen amb el soroll d'AWS, les regles es
tornen fràgils i l'arxiu s'omple d'esdeveniments que no interessen. Fes servir un bus propi.
Deixar l'edat màxima de l'esdeveniment en 24 hores. Un avís de repartiment lliurat 20 hores tard és
pitjor que una fallada visible. Ajusta MaximumEventAgeInSeconds al valor de negoci.
Reproduir sense FilterArns. Dispara totes les regles del bus i repeteix efectes que ja van passar.
És l'error més car d'aquesta lliçó.
Oblidar la DLQ de la destinació. Sense ella, el que no es lliura desapareix sense deixar rastre.
Posar ordres al bus. Si el detail-type és un verb en imperatiu, has reintroduït l'acoblament que
volies eliminar.
Canviar el detail sense pujar version. Trenques consumidors que no saps que existeixen i te
n'assabentes en producció.
Consell: una regla per intenció, no una regla amb cinc destinacions heterogènies. Les regles separades tenen la seva pròpia DLQ, la seva pròpia edat màxima i la seva pròpia mètrica, i es poden desactivar d'una en una durant un incident.
Consell: escriu el catàleg abans que el codi. La taula de source / detail-type / camps són deu
minuts de feina que eviten mesos d'esdeveniments incoherents.
Consell: activa l'arxiu des del primer dia. Costa cèntims i és l'única manera de recuperar el que un consumidor mal configurat es va perdre.
Exercicis
Exercici 1: encaminar el catàleg complet
Dissenya les regles de bus-mercadofresco per a aquests quatre requisits: (1) tots els
PedidoConfirmado van a cola-mercadofresco-almacen; (2) els PedidoConfirmado de franja 24h o
d'import ≥ 100 € van a més a la destinació d'API de l'ERP amb prioritat; (3) els StockBajo de productes
frescos (SKU que comencen per FRUT- o PESC-) amb menys de 5 unitats avisen alertas-mercadofresco;
(4) qualsevol esdeveniment de mercadofresco.* s'arxiva 90 dies.
Escriu els patrons JSON, digues quantes regles crees i per què, i quina transformació de l'entrada faries servir al requisit 3.
Exercici 2: el consumidor que es va perdre una tarda
El dimarts a les 09:00 el Luis desplega una versió de la Lambda d'analítica que llança una excepció en
arrencar. Ningú no ho detecta fins a les 15:00. La regla regla-mf-pedido-confirmado-analitica lliura
directament a aquella Lambda, sense cua. Hi ha arxiu actiu des de fa tres mesos.
Respon: (a) què ha passat amb els esdeveniments d'aquelles sis hores segons la configuració de reintents per defecte i segons una edat màxima de 3.600 s; (b) com recuperes les dades, amb l'ordre exacta; (c) quina precaució prens abans de llançar-la; (d) quins dos canvis d'arquitectura eviten que torni a passar; (e) quina alarma hauria avisat a les 09:05.
Exercici 3: SNS, EventBridge o Pipes
Decideix el servei i justifica-ho en dues frases: (a) tres equips volen les comandes confirmades, amb
filtres simples i la mínima latència possible; (b) cal cridar l'ERP del soci per HTTPS amb clau d'API i
com a màxim 12 peticions per segon; (c) cal avisar per SMS el tècnic de guàrdia; (d) cal llançar la
càrrega a Redshift cada dia a les 02:30 hora peninsular; (e) cal reaccionar als esborrats per TTL de
mercadofresco-carritos enriquint amb dades d'Aurora; (f) cal reaccionar que una instància EC2 passi a
terminated.
Solucions
Solució 1
Quatre regles més un arxiu. Se separen perquè cadascuna té destinació, edat màxima i DLQ propis, i perquè una regla amb patrons barrejats es torna il·legible.
(1) regla-mf-pedido-confirmado-almacen:
(2) regla-mf-pedido-prioritario-erp. L'OR entre camps diferents obliga a $or:
{
"source": ["mercadofresco.tienda"],
"detail-type": ["PedidoConfirmado"],
"$or": [
{ "detail": { "franja_entrega": ["24h"] } },
{ "detail": { "importe_eur": [{ "numeric": [">=", 100] }] } }
]
}Destinació destino-api-erp-almacen amb MaximumEventAgeInSeconds baix (900 s: una comanda urgent que
no arriba en 15 minuts s'ha de tractar a mà) i DLQ mercadofresco-eventbridge-fallidas.
(3) regla-mf-stock-bajo-fresco. Aquí sí que és AND entre camps: prefix de SKU i unitats.
{
"source": ["mercadofresco.almacen"],
"detail-type": ["StockBajo"],
"detail": {
"sku": [{ "prefix": "FRUT-" }, { "prefix": "PESC-" }],
"unidades_restantes": [{ "numeric": ["<", 5] }]
}
}Els dos prefix dins de la llista de sku són un OR, que és just el que es demana. Transformació de
l'entrada, perquè la destinació és un tema d'SNS que acaba al correu d'una persona:
{
"InputPathsMap": { "sku": "$.detail.sku", "queden": "$.detail.unidades_restantes" },
"InputTemplate": "\"Estoc critic: queden <queden> unitats de <sku>. Reposar avui.\""
}(4) No és una regla, és un arxiu amb patró {"source":[{"prefix":"mercadofresco."}]} i
--retention-days 90. Convé el prefix per no arxivar esdeveniments d'AWS que no aporten i sí que ocupen.
Solució 2
(a) Amb els valors per defecte (185 reintents, 24 hores), els esdeveniments de les 09:00 encara
s'estarien reintentant a les 15:00, i en arreglar la Lambda una part es lliuraria sola, tot i que amb
hores de retard i desordenada. Amb MaximumEventAgeInSeconds=3600, cada esdeveniment es descarta al cap
d'una hora de publicar-se: a les 15:00 tot el que és anterior a les 14:00 és a la DLQ de la destinació i
la resta continua reintentant. La segona configuració és preferible: converteix una degradació
silenciosa en un munt visible de missatges a la DLQ.
(b) Primer s'arregla la Lambda i es comprova amb un esdeveniment de prova. Després:
aws events start-replay --replay-name reproduccion-analitica-20260804 \
--event-source-arn arn:aws:events:eu-west-1:111122223333:archive/archivo-mercadofresco-eventos \
--event-start-time 2026-08-04T07:00:00Z --event-end-time 2026-08-04T13:00:00Z \
--destination '{"Arn":"arn:aws:events:eu-west-1:111122223333:event-bus/bus-mercadofresco",
"FilterArns":["arn:aws:events:eu-west-1:111122223333:rule/bus-mercadofresco/regla-mf-pedido-confirmado-analitica"]}'Les hores van en UTC: les 09:00–15:00 peninsulars d'agost són 07:00–13:00 UTC. Equivocar-s'hi és un clàssic.
(c) Tres precaucions. FilterArns obligatori, o la reproducció dispararia totes les regles i
tornaria a avisar el magatzem i a facturar comandes de fa sis hores. Verificar que el consumidor és
idempotent, perquè part dels esdeveniments es va poder lliurar abans de fallar i la reproducció els
repetirà. I buidar o revisar abans la DLQ de la destinació, per no reprocessar dos cops per dos camins.
(d) Primer, posar una cua entre la regla i la Lambda: amb SQS, sis hores de fallada deixen 5.000 missatges esperant i es processen en arreglar el problema sense reproduir res; és la mateixa lliçó de 07-02 aplicada a EventBridge. Segon, DLQ a la destinació més alarma, perquè el senyal aparegui en minuts. Com a tercera mesura, un desplegament amb verificació de salut que reverteixi sol, que és justament el tema del mòdul 8.
(e) Una alarma sobre FailedInvocations de la regla, llindar > 0 en un període de 5 minuts, cap a
alertas-mercadofresco. Complementària: Errors de la funció Lambda. Qualsevol de les dues hauria
avisat a les 09:05 en lloc de a les 15:00.
Solució 3
(a) SNS. Fan-out pur, filtres simples i requisit de latència mínima: SNS lliura en desenes de mil·lisegons davant dels centenars d'EventBridge, i ja està muntat. Cada equip amb la seva cua subscrita.
(b) EventBridge amb destinació d'API. És exactament el seu cas d'ús: gestiona la clau en una connexió
recolzada per Secrets Manager, aplica invocation-rate-limit-per-second 12 i reintenta amb DLQ, tot
sense escriure una línia de codi.
(c) SNS. És l'únic dels tres que lliura SMS. A més, l'alarma de CloudWatch ja hi publica de manera nativa.
(d) EventBridge Scheduler. Necessita zona horària amb horari d'estiu (Europe/Madrid), que les
regles programades clàssiques no admeten, i la finestra flexible evita el pic de connexions contra el
lector d'Aurora.
(e) EventBridge Pipes. És l'únic que consumeix DynamoDB Streams amb filtratge abans de facturar i amb
un pas d'enriquiment integrat. Fer-ho amb una Lambda subscrita al stream obligaria a filtrar i enriquir a
mà, processant —i pagant— els milions de MODIFY que no interessen.
(f) EventBridge, bus default. Els esdeveniments d'EC2 arriben sols i són gratuïts; no hi ha res per
publicar. Una regla amb patró sobre aws.ec2 i destinació alertas-mercadofresco.
Conclusió
MercadoFresco ja no té un tema per tipus de fet, sinó un bus on conviuen PedidoConfirmado,
PedidoCancelado, StockBajo i RepartoAsignado, i on regles amb patrons JSON decideixen on va
cadascun mirant-ne el contingut: la franja, l'import, la província, el prefix del SKU. L'ERP del soci rep
el seu propi vocabulari gràcies a la transformació de l'entrada, sense que ningú reanomeni res a
l'esdeveniment. Les tasques nocturnes —la càrrega a analitica.hechos_pedidos i la consolidació de
cistelles— corren amb programador-mf-carga-nocturna en hora peninsular i amb finestra flexible. Els
incidents d'infraestructura i les troballes de Trusted Advisor arriben sols, sense que ningú hagi d'anar
a mirar. I els Streams de mercadofresco-carritos, presentats a 06-02 i sense fer servir fins avui,
alimenten per fi un esdeveniment de negoci a través de pipe-mf-carritos-abandonados, amb un filtre que
distingeix l'esborrat del TTL de l'esborrat per compra.
Dues idees s'emporten el pes de la lliçó. La primera és que l'encaminament per contingut canvia qui
decideix: ja no és l'emissor qui reparteix la feina, sinó una regla declarativa que es modifica sense
desplegar codi. La segona és que un esdeveniment és una API pública, amb tot el que això implica: es
pot afegir, no es pot treure, i sense version al detall no hi ha migració possible. Entremig queda
archivo-mercadofresco-eventos, la xarxa de seguretat que converteix «hem perdut sis hores de dades»
en una reproducció d'una sola ordre —sempre amb FilterArns, o el remei serà pitjor que la
malaltia—.
Però fixa't en el que continua sense resoldre. Tot el que hem muntat és coreografia: cada component reacciona al que veu i ningú no té la foto completa. Funciona de meravella per a fets independents, i es trenca quan el procés té passos que depenen els uns dels altres i cal desfer el que s'ha fet si alguna cosa falla a mitges. La comanda de MercadoFresco és exactament això: cobrar, reservar estoc, demanar la preparació al magatzem —que triga entre dos minuts i una hora i la confirma una persona amb un lector de codis—, assignar repartiment i confirmar al client. Si el magatzem no pot preparar la caixa perquè el peix ha arribat en mal estat, cal tornar el cobrament i alliberar l'estoc, i amb esdeveniments solts ningú no sap en quin punt era el procés ni què toca compensar.
A 07-04, «AWS Step Functions», passem de la coreografia a l'orquestració: una màquina d'estats,
mercadofresco-procesar-pedido, que coneix el procés sencer, desa en quin pas va, reintenta amb retrocés
exponencial, espera que un humà confirmi mitjançant un testimoni de retorn, processa les 900
confirmacions del divendres en paral·lel amb Map distribuït, i —el més important— sap desfer el que
ja havia fet quan alguna cosa surt malament.
Curs d'AWS
Mòdul 1: Introducció a AWS
- Què és AWS?
- Configuració del teu compte d'AWS
- Infraestructura global d'AWS
- Consola d'administració d'AWS
- AWS CLI i SDK
Mòdul 2: Serveis principals d'AWS
Mòdul 3: Xarxes i lliurament de contingut
- Amazon VPC
- Grups de seguretat i llistes de control d'accés
- Elastic Load Balancing
- Amazon CloudFront
- Route 53
Mòdul 4: Seguretat i identitat
- AWS Identity and Access Management (IAM)
- AWS Key Management Service (KMS)
- Secrets Manager i Parameter Store
- AWS Shield
- AWS WAF
Mòdul 5: Monitoratge i gestió
- Amazon CloudWatch
- AWS X-Ray i traçabilitat distribuïda
- AWS CloudTrail
- AWS Config
- AWS Trusted Advisor
Mòdul 6: Bases de dades
- Com triar la base de dades adequada
- Amazon DynamoDB
- Amazon Aurora
- Amazon Redshift
- Amazon ElastiCache
Mòdul 7: Integració d'aplicacions
- Amazon SQS
- Amazon SNS
- Amazon EventBridge
- AWS Step Functions
- Patrons d'integració: idempotència, reintents i cues de missatges fallits
