OtelMetrics.registerProducer: readers bound before one that fails to bind are never shut down and keep exporting
Los mantenedores suelen responder en 1 día
Ya se ha fusionado un pull request relacionado.
- #9389 de @effect-bot — fusionado
Evaluación
- Dificultad
- 2/5
- Tiempo estimado
- 1-3 horas
- Aptitud para principiantes
- 75/100
- Tipo de issue
- Error
- Claridad
- Bien especificado
- Estado de actividad
- Activo
- Stack tecnológico
- typescript
- Área
- observability
Línea de trabajo
El paso de adquisición de registerProducer en packages/opentelemetry/src/OtelMetrics.ts (alrededor de las líneas 82-99) vincula cada reader dentro de un único Effect.sync, así que si se lanza una excepción a mitad de camino, los readers vinculados antes quedan sin finalizer. Lee el bloque de adquisición y el finalizer de acquireRelease, y luego ejecuta los dos casos de registerProducer en packages/opentelemetry/test/OtelMetrics.test.ts. Está terminado cuando pasa el test que espera que los readers ya vinculados se apaguen tras un bind fallido, y sigue pasando el test existente de apagado al cerrar el scope.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
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.
- Lenguaje dominante
- TypeScript
- Estrellas
- 16.7k
- Forks
- 808
- Merge medio
- 11 h 33 min
- PR fusionados (30 d)
- 855
Preparar el entorno
Este proyecto no incluye contenedor de desarrollo, Dockerfile ni guía de contribución, así que la configuración corre por tu cuenta: empieza por su README y consulta nuestra guía para la primera contribución para los pasos generales.
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de Effect-TS/effect
-
`fromJsonSchemaDocument`: import open `patternProperties`Posiblemente ocupada @effect-bot la tomó hoy. Abierto
Effect-TS/effect#10048 · 1 asignado ·
Los mantenedores suelen responder en 1 día
-
`fromJsonSchemaDocument`: intersect an object with `anyOf` branches that re-declare an enum propertyAbierto
Dificultad 4/5 3-5 días Aptitud para principiantes 42/100
Los mantenedores suelen responder en 1 día
-
`fromJsonSchemaDocument`: import `dependentRequired` (draft-07 `dependencies`)Posiblemente ocupada @effect-bot la tomó hoy. Abierto
Effect-TS/effect#10046 · 1 asignado ·
Los mantenedores suelen responder en 1 día
-
`fromJsonSchemaDocument`: import `if` / `then` / `else`Posiblemente ocupada @effect-bot la tomó hoy. Abierto
Effect-TS/effect#10045 · 1 asignado ·
Los mantenedores suelen responder en 1 día
-
`fromJsonSchemaDocument`: import the `not` keywordPosiblemente ocupada @effect-bot la tomó hoy. Abierto
Effect-TS/effect#10044 · 1 asignado ·
Los mantenedores suelen responder en 1 día
Todos los issues de Effect-TS/effect
Issues similares
-
[Bug]: Pen taps on sidebar rows start a drag and lose their clickPosiblemente ocupada @makhnatkin la tomó hoy. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 62/100
Los mantenedores suelen responder en 1 día
-
enhancement
Dificultad 2/5 1-3 horas Aptitud para principiantes 70/100
b310-digital/teammapper#1515 ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 79/100
puckeditor/puck#1884 ·
Los mantenedores suelen responder en 1 día
-
bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 65/100
outline/outline#14378 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
nicobailon/pi-web-access#642 ·
Los mantenedores suelen responder en 1 día