Effect-TS / effect

An ecosystem of tools for building production-grade applications in TypeScript.
https://effect.website
MIT License
6.95k stars 217 forks source link

Find ways to manage ressources in frameworks with hot-reload to Help Effect-ts integration #992

Open sledorze opened 2 years ago

sledorze commented 2 years ago

We have a problem with auto-reload and ressource release. For example with NextJs and Prisma Client, when NextJs reloads, there's no way for Managed to be run.

On the Prisma website, it is said to basically store a global (which doesn't really solve the actual issue).

From @mikearnaldi past efforts, there's no solution to that issue ans from @schickling we may ask for some help from NextJs team (acknowledging that the problem is broader than this lib but it's pretty trendy nowadays).

The solution has to be found, this issue is here to collect and iterate on possibilities

SamB commented 1 year ago

Well, FinalizationRegistry might possibly be helpful -- they don't guarantee that finalizers will be called under any circumstances at all -- but it does exist, as does WeakRef -- though that's not guaranteed to actually be weak, either. (All WeakRefs to a given object are, however, guarenteed to be broken at the same time, and if any finalizers for an object are run, the WeakRefs are guaranteed to have been broken before that.)

WeakMap and WeakSet certainly won't help -- you can't iterate over them, and it's the keys that are weakly referenced.

So, for cleanups of semantic importance or having to do with precious, off-heap resources like file descriptors/OS-level handles or external memory allocations, you would NOT be able to rely on FinalizationRegistry (which might never run the finalizer) or have much use for WeakRef (losing the reference to the file handle, etc. is obviously not useful), and would just need a global registry, stashed someplace that you never try to reload...

For cleanups that merely reduce excess memory use, weakrefs/finalizers might be fine, though it would be better to think about WeakSet/WeakMap first because those can be cleaned up asynchronously, without waiting for the next time the host's event loop decides to allow it. (See https://tc39.es/ecma262/#sec-weakref-processing-model for details.) Also, finalization-based are extremely difficult to reason about; it is quite easy to accidentally retain a strong reference somehow or other, which would render the finalizer worse than useless (though at least, since FinalizationRegistry uses a single callback for the whole registry, you're much less likely to end up capturing a reference to the object in the callback's closure -- which might happen in some systems even if the callback doesn't actually reference the relevant variable).

WeakRefs are also more efficient than finalizers: if none of the WeakRefs to an otherwise-unreachable object were created or dereferenced since the last time the host invoked the ClearKeptObjects() abstract operation, the implementation may break the WeakRefs without waiting for the host's event loop to invoke ClearKeptObjects() again. Furthermore, finalizers have to run user code, and in practice I think anything kept live by a registry entry's [[HeldValue]] would have to wait for the next pass of garbage collection to get cleaned up, whereas weak references can't themselves require multiple cleanup passes.

... um, feel free to minimize this comment, I didn't mean to ramble so much ...