`Effect.request` batch pool retains completed request context through shared closures
Los mantenedores suelen responder en 1 día
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 4/5
- Tiempo estimado
- 1-2 días
- Aptitud para principiantes
- 55/100
- Tipo de issue
- Error
- Claridad
- Bien especificado
- Estado de actividad
- Activo
- Stack tecnológico
- node.js, typescript
- Área
- backend, performance
Línea de trabajo
Start by comparing the published 4.1.0 implementation of Effect.request and its batch pool with the 4.0.2 change that extracted batch construction into a module-level makeBatch function. Run the supplied node --expose-gc repro.mjs reproduction before and after any change; done means the completed request no longer retains its originating context, while preserving batch cleanup behavior.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
What version of Effect is running?
4.1.0. Also reproduced with 4.0.6.
What steps can reproduce the bug?
Install Effect:
npm install [email protected]
Save the following as repro.mjs, then run node --expose-gc repro.mjs:
import { AsyncLocalStorage } from 'node:async_hooks';
import { Effect, Exit, Request, RequestResolver } from 'effect';
class ExampleRequest extends Request.Class {}
const storage = new AsyncLocalStorage();
const resolver = RequestResolver.make((entries) =>
Effect.sync(() => {
for (const entry of entries) {
entry.completeUnsafe(Exit.succeed('done'));
}
}),
);
let reference;
await storage.run({ data: new Array(100_000).fill('example') }, async () => {
reference = new WeakRef(storage.getStore());
await Effect.runPromise(
Effect.scoped(
Effect.gen(function* () {
const signal = yield* Effect.abortSignal;
return yield* Effect.request(
new ExampleRequest({ signal }),
resolver,
);
}),
),
);
});
for (let i = 0; i < 5; i++) {
await new Promise(setImmediate);
global.gc();
}
console.log({ contextRetained: !!reference.deref() });
The request completes successfully and the scope closes, but the asynchronous context remains reachable after garbage collection. This reproduction does not perform network I/O.
What is the expected behavior?
{ contextRetained: false }
The completed request should not keep its originating asynchronous context alive through the reusable batch pool.
What do you see instead?
{ contextRetained: true }
Observed in five separate processes with Effect 4.1.0 and five with 4.0.6.
Additional information
Environment:
- Node.js: v24.22.1
- V8: 13.6.233.17-node.58
- OS/architecture: macOS arm64
Investigation of Effect 4.0.2 identified this heap retaining path:
module-level batchPool
→ batch.run
→ onExit callback
→ shared addEntry lexical context
→ completed request entry
→ request.signal
→ signal.reason / asynchronous stack
→ AsyncContextFrame
→ AsyncLocalStorage store
The suspected cause is V8 sharing the enclosing lexical context between the persistent batch callbacks and request-specific callbacks created inside addEntry. Clearing the batch's explicit fields does not remove this closure reference.
Extracting batch construction into a separate module-level makeBatch function in 4.0.2, while preserving its existing cleanup logic, changed this reproduction to contextRetained: false in five separate processes.
The published 4.1.0 implementation still creates these batch callbacks inside addEntry, and the reproduction above still reports retention.
This is retention through a bounded reusable pool, not a claim of unlimited pool growth. The proposed extraction was tested against 4.0.2; it has not yet been applied and validated against 4.1.0.
- Lenguaje dominante
- TypeScript
- Estrellas
- 16.7k
- Forks
- 808
- Merge medio
- 10 h 17 min
- PR fusionados (30 d)
- 850
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
-
Dificultad 1/5 Menos de una hora Aptitud para principiantes 82/100
Los mantenedores suelen responder en 1 día
-
@effect/ai-anthropic: text_editor_20250728 insert decodes `new_str`, but the API sends `insert_text`Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 75/100
Los mantenedores suelen responder en 1 día
-
[email protected]: crypto/KeyFormat declarations require the global JsonWebKey, breaking Node-only type-checksPosiblemente ocupada @effect-bot la tomó hace 1 día. Abierto
Effect-TS/effect#10115 · 1 asignado ·
Los mantenedores suelen responder en 1 día
-
sql-pg: send several statements in one extended-query Sync (transaction-local context without extra round trips)Posiblemente ocupada @effect-bot la tomó hace 1 día. Abierto
Effect-TS/effect#10113 · 1 asignado ·
Los mantenedores suelen responder en 1 día
-
CircuitBreaker: record an outcome without guarding the callPosiblemente ocupada @effect-bot la tomó hace 1 día. Abierto
Effect-TS/effect#10110 · 1 asignado ·
Los mantenedores suelen responder en 1 día
Todos los issues de Effect-TS/effect
Issues similares
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
-
area:desktop area:ui bug platform:macos
Dificultad 2/5 1-3 horas Aptitud para principiantes 67/100
anthropics/claude-code#106183 ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 76/100
-
Dificultad 1/5 1-3 horas Aptitud para principiantes 76/100
Los mantenedores suelen responder en 1 día
-
reproduced
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
anomalyco/opencode#60558 · 1 comentario ·
Los mantenedores suelen responder en 1 día