OtelMetrics.registerProducer: readers bound before one that fails to bind are never shut down and keep exporting
I maintainer di solito rispondono entro 1 giorno
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 2/5
- Tempo stimato
- 1-3 ore
- Idoneità per principianti
- 75/100
- Tipo di issue
- Bug
- Chiarezza
- Specificata chiaramente
- Stato di attività
- Attiva
- Stack tecnologico
- typescript
- Ambito
- observability
Direzione di ricerca
Il passo di acquisizione di registerProducer in packages/opentelemetry/src/OtelMetrics.ts (intorno alle righe 82-99) associa ogni reader dentro un unico Effect.sync, quindi un'eccezione lanciata a metà lascia i reader già associati senza finalizer. Leggi il blocco di acquisizione e il finalizer di acquireRelease, poi esegui i due casi di registerProducer in packages/opentelemetry/test/OtelMetrics.test.ts. È completato quando passa il test che si aspetta che i reader già associati vengano chiusi dopo un bind fallito e continua a passare il test esistente sulla chiusura alla chiusura dello scope.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
What version of Effect is running?
4.0.5 (effect, @effect/opentelemetry; @opentelemetry/sdk-metrics 2.12.0, Node 26.11.1). registerProducer is unchanged on main at c9a1e72.
What steps can reproduce the bug?
When the reader thunk given to OtelMetrics.layer or registerProducer returns several readers and a later one throws from setMetricProducer, the build dies but the earlier readers stay bound and are never shut down. For example, the later reader may already be registered with a MeterProvider, so the SDK throws "MetricReader can not be bound to a MeterProvider again.". A PeriodicExportingMetricReader among the earlier readers keeps exporting Effect metrics after the scope has closed. If the build failure is handled, for example with a Layer.catchCause fallback, it keeps exporting for the life of the process with no owner.
This test, added to packages/opentelemetry/test/OtelMetrics.test.ts (with Cause and Exit imports), fails on main. The first case passes:
describe("registerProducer", () => {
class Reader extends MetricReader {
shutdowns = 0
protected onShutdown(): Promise<void> {
this.shutdowns++
return Promise.resolve()
}
protected onForceFlush(): Promise<void> {
return Promise.resolve()
}
}
it.effect("shuts down every reader when the scope closes", () =>
Effect.gen(function*() {
const services = yield* Effect.context<never>()
const producer = new internal.MetricProducerImpl(resourceFromAttributes({}), services)
const first = new Reader()
const second = new Reader()
yield* OtelMetrics.registerProducer(producer, () => [first, second]).pipe(Effect.scoped)
assert.deepStrictEqual([first.shutdowns, second.shutdowns], [1, 1])
}))
it.effect("shuts down readers bound before a reader that fails to bind", () =>
Effect.gen(function*() {
const services = yield* Effect.context<never>()
const producer = new internal.MetricProducerImpl(resourceFromAttributes({}), services)
const fresh = new Reader()
const alreadyBound = new Reader()
alreadyBound.setMetricProducer(producer)
const exit = yield* OtelMetrics.registerProducer(producer, () => [fresh, alreadyBound]).pipe(
Effect.scoped,
Effect.exit
)
assert.isTrue(Exit.isFailure(exit) && Cause.hasDies(exit.cause))
assert.strictEqual(fresh.shutdowns, 1)
}))
})
What is the expected behavior?
Every reader that registerProducer bound is shut down when the acquisition fails, as the release does when the scope closes. Two separate registerProducer calls in one scope already do this: when the second call dies, the first call's finalizer shuts its reader down.
What do you see instead?
expected +0 to equal 1: fresh is bound but never shut down.
The published 4.0.5 packages behave the same way. In that run the readers were PeriodicExportingMetricReaders with a 50 ms interval. In the 300 ms after the failed Effect.provide(OtelMetrics.layer(() => [a, alreadyBound])), reader a exported 5 more times, and its exporter's shutdown was never called.
Additional information
The acquire binds every reader inside one Effect.sync (OtelMetrics.ts#L82-L99). When setMetricProducer throws for a later reader, the earlier ones are already bound. The throw becomes a defect, and acquireRelease adds its finalizer only after acquisition succeeds (effect.ts#L4153-L4155), so nothing shuts them down. main still has the same code. Shutting down the readers bound so far when a later bind throws would cover it. The v3 Metrics.registerProducer (0.64.1) binds readers the same way.
- Lingua principale
- TypeScript
- Stelle
- 16.7k
- Fork
- 808
- Merge medio
- 9h 42m
- PR unite (30g)
- 669
Preparare l'ambiente
Questo progetto non fornisce container di sviluppo, Dockerfile né guida per i contributori, quindi l'ambiente è a tuo carico: parti dal suo README e consulta la nostra guida al primo contributo per i passaggi generali.
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di Effect-TS/effect
-
BrowserWorkerRunner: port finalizer throws when the worker global has no close() (Bun)Forse già presa @santiago-ramos-02 l’ha presa 16 giorni fa. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
Effect-TS/effect#8635 · 3 commenti ·
I maintainer di solito rispondono entro 1 giorno
-
Support {self: this} for fnUntracedForse di nuovo libera @ArjunCodess l’ha presa 27 giorni fa e non c’è nessuna pull request aperta. Apertaenhancement
Difficoltà 2/5 1-3 ore Idoneità per principianti 70/100
Effect-TS/effect#8101 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 3/5 1-2 giorni Idoneità per principianti 45/100
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 3/5 Mezza giornata Idoneità per principianti 52/100
I maintainer di solito rispondono entro 1 giorno
-
RcMap, RcRef and ScopedCache: a dying release is lost on idle expiry, an interrupted lookup, or expiry during `keys`/`values`/`entries`Forse già presa @effect-bot l’ha presa oggi. Aperta
Effect-TS/effect#9372 · 1 assegnatario ·
I maintainer di solito rispondono entro 1 giorno
Tutte le issue di Effect-TS/effect
Issue simili
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 67/100
agilepathway/label-checker#739 · 4 commenti ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 68/100
CopilotKit/OpenBot#800 ·
I maintainer di solito rispondono entro 1 giorno
-
Endpoint links in the tag operations list are below the 24px target sizeForse già presa @AdzerKI l’ha presa oggi. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 79/100
ehmpathy/rhachet-roles-bhuild#471 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 73/100
I maintainer di solito rispondono entro 1 giorno