Hacktoberfest 2026: los issues que los mantenedores marcaron para octubre, abiertos y aptos para principiantes. Explorar issues de Hacktoberfest

`Effect.request` batch pool retains completed request context through shared closures

Abierto
#10,114 0 comentarios 0 reacciones 0 asignados Ver en GitHub

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

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

bug
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

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Más de Effect-TS/effect

Todos los issues de Effect-TS/effect

Issues similares

Más issues de TypeScript

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.