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
Una pull request collegata è già stata integrata.
- #9389 di @effect-bot — integrata
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
- 10h 22m
- PR unite (30g)
- 771
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 19 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 30 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
-
HashMap.set keeps the old value when the new one is Equal to itForse già presa @schutzelaars l’ha presa oggi. Aperta
Difficoltà 3/5 1-2 giorni Idoneità per principianti 58/100
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 3/5 1-2 giorni Idoneità per principianti 74/100
I maintainer di solito rispondono entro 1 giorno
-
OpenApi: optional query and header parameters are documented as nullableForse già presa @Marve10s l’ha presa 2 giorni fa. Aperta
Difficoltà 4/5 3-5 giorni Idoneità per principianti 57/100
I maintainer di solito rispondono entro 1 giorno
Tutte le issue di Effect-TS/effect
Issue simili
-
area: aria/combobox gemini-triaged
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
angular/components#33973 ·
I maintainer di solito rispondono entro 1 giorno
-
bug priority: P2
Difficoltà 1/5 1-3 ore Idoneità per principianti 84/100
I maintainer di solito rispondono entro 1 giorno
-
[bug] status, list and push crash with an uncaught NotInitializedError stack trace when teamai is not initializedForse già presa @jay23606 l’ha presa oggi. Apertabug good first issue help wanted
Difficoltà 2/5 1-3 ore Idoneità per principianti 84/100
Tencent/teamai-cli#1227 ·
I maintainer di solito rispondono entro 1 giorno
-
[Tool]: YapAperta
Difficoltà 1/5 1-3 ore Idoneità per principianti 62/100
withkarann/aifoxx#417 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 86/100
sindresorhus/eslint-plugin-unicorn#3921 ·
I maintainer di solito rispondono entro 1 giorno