refactor(infra): split de drivers pesados a subpaquetes + fix TestSSEHandler
Mueve duckdb_open, clickhouse_open, postgres_open, matrix_* y keyring_token_store
del paquete monolitico functions/infra a subpaquetes propios
(functions/infra/{duckdb,clickhouse,postgres,matrix,keyring}). El paquete infra ya
no importa los drivers (go-duckdb, clickhouse-go, pgx, mautrix, go-keyring), por lo
que las apps que solo usan funciones ligeras (process, cron, http, sqlite) dejan de
arrastrarlos. Reduccion de binarios: dag_engine 72->10MB, registry_api 70->8.7MB,
services_api 70->9MB, call_monitor 68->6.6MB, sqlite_api 70->8.9MB.
Los IDs del registry se mantienen estables (domain: infra en frontmatter). Se
preservan los build tags goolm/libolm de matrix_crypto_init.
Tambien corrige TestSSEHandler: el test leia el body con un unico Read() que con
HTTP chunked solo capturaba el primer evento; ahora usa io.ReadAll hasta EOF.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
---
|
||||
name: matrix_sync_service
|
||||
kind: function
|
||||
lang: go
|
||||
domain: infra
|
||||
version: "0.1.0"
|
||||
purity: impure
|
||||
signature: "func MatrixSyncService(ctx context.Context, cfg MatrixSyncServiceConfig) (*MatrixSyncServiceHandle, error)"
|
||||
description: "Arranca el sync loop de mautrix contra Synapse en background con backoff exponencial, emite eventos Matrix normalizados via canal Go y expone funcion de stop idempotente."
|
||||
tags: [matrix, mautrix, sync, longpoll, reconnect, goroutine, channels, infra, matrix-mas]
|
||||
params:
|
||||
- name: ctx
|
||||
desc: "Context padre. Si se cancela, la goroutine sale limpiamente y cierra los channels."
|
||||
- name: cfg.Client
|
||||
desc: "*mautrix.Client ya inicializado con credenciales (HomeserverURL, AccessToken, UserID). Usar matrix_client_init para crearlo. Obligatorio."
|
||||
- name: cfg.InitialBackoffMS
|
||||
desc: "Milisegundos de espera inicial entre reintentos tras error de sync. Default: 1000 (1s)."
|
||||
- name: cfg.MaxBackoffMS
|
||||
desc: "Techo del backoff exponencial en ms. Default: 60000 (60s)."
|
||||
- name: cfg.ChannelBuffer
|
||||
desc: "Capacidad del buffer del canal Events. Si el consumer va lento y el buffer se llena, el sync se bloquea hasta que el consumer drene. Default: 256."
|
||||
output: "*MatrixSyncServiceHandle con Events <-chan MatrixSyncEvent (canal de eventos normalizados), Errors <-chan error (errores transitorios no fatales), Stop func() (cancela y cierra todo, idempotente)."
|
||||
uses_functions: []
|
||||
uses_types: []
|
||||
returns: []
|
||||
returns_optional: false
|
||||
error_type: "error_go_core"
|
||||
imports:
|
||||
- "maunium.net/go/mautrix"
|
||||
- "maunium.net/go/mautrix/event"
|
||||
- "maunium.net/go/mautrix/id"
|
||||
tested: true
|
||||
tests:
|
||||
- "RecibeMensajeYStop"
|
||||
- "BackoffRecovery"
|
||||
- "Error401NoExit"
|
||||
- "StopIdempotente"
|
||||
- "CtxCancelCierraChannels"
|
||||
test_file_path: "functions/infra/matrix/matrix_sync_service_test.go"
|
||||
file_path: "functions/infra/matrix/matrix_sync_service.go"
|
||||
---
|
||||
|
||||
## Ejemplo
|
||||
|
||||
```go
|
||||
ctx := context.Background()
|
||||
h, err := MatrixSyncService(ctx, MatrixSyncServiceConfig{
|
||||
Client: client, // *mautrix.Client de matrix_client_init
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer h.Stop()
|
||||
|
||||
// Consumir errores transitorios en goroutine separada
|
||||
go func() {
|
||||
for e := range h.Errors {
|
||||
log.Println("matrix sync error:", e)
|
||||
}
|
||||
}()
|
||||
|
||||
// Loop de eventos (bloquea hasta que h.Stop() se llame o ctx sea cancelado)
|
||||
for ev := range h.Events {
|
||||
fmt.Printf("[%s] %s: %s\n", ev.Type, ev.Sender, ev.Body)
|
||||
}
|
||||
```
|
||||
|
||||
## Cuando usarla
|
||||
|
||||
Usar despues de `MatrixClientInit` (y opcionalmente `MatrixCryptoInit`) para recibir el stream de eventos de Matrix en tiempo real. Es el servicio long-running central de cualquier cliente Matrix: matrix_client_pc, admin_panel, bots, monitores. Un solo `MatrixSyncService` por client, durante toda la vida de la aplicacion.
|
||||
|
||||
## Gotchas
|
||||
|
||||
- **Solo UN Sync por client**: dos goroutines llamando `SyncWithContext` simultaneamente sobre el mismo client rompe el `since` token y produce duplicados o perdidas. Esta funcion garantiza una sola goroutine de sync si es llamada una sola vez. NO llamar `MatrixSyncService` dos veces sobre el mismo `*mautrix.Client`.
|
||||
- **Crypto antes del Sync**: mensajes `m.room.encrypted` que llegan antes de inicializar `MatrixCryptoInit` quedan sin descifrar (emitidos con `Type:"encrypted"`, `Body:""`, `Raw:*event.Event`). Inicializar crypto siempre ANTES de llamar a esta funcion.
|
||||
- **Buffer de channel**: si el consumer no drena `Events` con suficiente rapidez, el sync se bloquea en el punto de emision. Synapse puede acumular deltas. Mantener el consumer rapido o aumentar `ChannelBuffer`.
|
||||
- **Errores fatales (401/M_UNKNOWN_TOKEN)**: no cierran el servicio automaticamente — se emiten a `Errors` y el servicio espera con backoff maximo. El caller decide llamar `Stop()` y re-autenticar.
|
||||
- **Stop idempotente**: llamar `Stop()` multiples veces es seguro; no causa panic.
|
||||
- **Build tag**: el paquete `infra` requiere `-tags goolm` para compilar tests sin libolm (dependencia C de la crypto de mautrix). Los tests usan `//go:build goolm`.
|
||||
Reference in New Issue
Block a user