🧪 Problem-Driven Systems Lab

🐹 Caso 08 — Go 1.23#

⬅️ Caso 08 · ⚖️ Comparativa de los 7 stacks · 🐹 Perfil de Go · 🧬 Todos los perfiles

Stack Go operativo del caso 08. Cutover big-bang que rompe consumers vs proxy de compatibilidad + bus de eventos.

Primitivas nativas#

PrimitivaRol
chan busEvent bufferizadoBus de eventos. Publicacion asincrona y desacoplada del request.
select con defaultPublicar sin bloquear: si el buffer esta lleno, se descarta el evento en vez de frenar trafico.
goroutine suscriptoraConsume a su ritmo, en su propio hilo de ejecucion.
funcion como ACLcompatProxy(old) new — el adapter de contrato es una funcion, no una clase.

Contraste#

Big-bang — el modulo nuevo solo entiende {price, currency}:

go
// consumer manda {sku, cost_usd} → contract_violation
"reason": "new module expects {price, currency}; consumer sent {sku, cost_usd}"

Compatible — el proxy traduce en vuelo:

go
func compatProxy(old priceRequestOld) priceRequestNew {
    return priceRequestNew{SKU: old.SKU, Price: old.CostUSD * 1.0, Currency: "USD"}
}

Y el avance del cutover se publica sin bloquear al consumer:

go
func emit(name string) {
    select {
    case cutoverBus <- busEvent{At: ..., Event: name}:
    default:                                   // buffer lleno → se descarta
    }
}

Rutas#

RutaQue muestra
/healthliveness
/pricing-bigbang?consumer=checkout&sku=ABC&cost_usd=100contract_violation
/pricing-compatible?consumer=checkout&sku=ABC&cost_usd=100traduce a {price, currency}, cutover_done: true
/flowsprogreso del cutover por consumer + eventos recientes
/diagnostics/summaryllamadas, proxy hits y contract tests por variante
/reset-labreinicia progreso y eventos

Hub#

docker compose -f compose.go.yml up -d --build
curl "http://127.0.0.1:8600/08/pricing-compatible?consumer=checkout&sku=ABC&cost_usd=100"
curl http://127.0.0.1:8600/08/flows

Canal en vez de EventEmitter#

Java modela el bus con CopyOnWriteArrayList<Consumer<Event>>; .NET con un event del CLR; Node con EventEmitter. Los tres comparten una propiedad que rara vez se nota hasta que duele: el emit() corre los subscribers en el thread del request. Un subscriber lento penaliza al consumer que disparo el evento.

Aca emit() empuja al canal y vuelve. La goroutine suscriptora consume despues, por su cuenta. La publicacion queda desacoplada del consumo sin montar una cola externa.

El select con default agrega una decision explicita que los otros stacks suelen dejar implicita: si el buffer se llena, se pierde telemetria en vez de frenar trafico. Esta escrita en dos lineas y es auditable. Es el mismo trade-off de backpressure que el caso 15 del roadmap estudia a fondo.

Ver esta carpeta en GitHub ↗