The current implementation of
withCleanupHook :: (Task a) (Task b) -> Task b | iTask a & iTask b, creates the cleanup hook as top task. Evaluation is then scheduled when the actual task is destroyed. This causes several issues:
- This causes memory leaks, as non-session top level tasks seem to never be destroyed.
- There is no way to pass information from the actual to the cleanup task (other than SDSs with global scope). If using a local SDS (created using
withShared) in both tasks, the SDS is already deleted when the cleanup task is evaluated. This currently causes a silent failure which complicates debugging.
- If the server is halted, all tasks are destroyed. With the current implementation the cleanup task is destroyed before the actual task, which changes semantics.
- Having cleanup hooks at the top level is conceptually not very neat, as there is no relation to the actual task. (It is also required to put a special attribute on cleanup tasks to hide them.)
I see the following solutions:
1: Assume that the cleanup task is stable with a single evaluation and execute it immediately when the task is destroyed.
- No memory leaks
- The cleanup tasks can still read all local SDSs used by the actual task.
- The semantics is clear and the implementation straightforward, in the sense that all effects are handled within the implementation of
- We can handle exceptions thrown in the cleanup task.
- No cleanup tasks which are not stable with a single evaluation are possible. This especially seems to be useful for reading asynchronous SDSs.
2: Fix the problems of the current implementation, but still start a new top level task. There has to be a way to pass information to the cleanup task (maybe
withCleanupHook :: (b -> Task a) (Task b) -> Task b).
- One can perform async operations in the cleanup task.
- Even if the cleanup tasks are destroyed when becoming stable, it's hard to detect memory leaks due to cleanup tasks which never become stable.
- We cannot handle exceptions of the cleanup task (but should as least trace them).
- The implementation is less straightforward.
3: We can also choose for both variants or make the task configurable. Or we evaluate the cleanup task once and continue in the background in case it doesn't become stable.
- more flexibility
- more complexity