Skip to content

Conversation

@edsko
Copy link

@edsko edsko commented Jan 24, 2026

The structure of mainThread in runServerWithOptions was

mainThread = do
    ...
    Async.withAsyncWithUnmask ... $ \theNewAsync ->
      mainThread

This means that every async created (to deal with incoming requests) are retained for the lifetime of the server: this in turn holds on the corresponding ThreadIds, and therefore the corresponding TSOs, resulting in a memory leak.

In this commit we instead maintain an IORef of all app threads, so that we can kill them if need be; every thread unregisters itself when it completes.

The structure of `mainThread` in `runServerWithOptions` was

```hs
mainThread = do
    ...
    Async.withAsyncWithUnmask ... $ \theNewAsync ->
      mainThread
```

This means that every async created (to deal with incoming requests) are
retained for the lifetime of the server: this in turn holds on the
corresponding `ThreadId`s, and therefore the corresponding TSOs, resulting in a
memory leak.

In this commit we instead maintain an `IORef` of all app threads, so that we
can kill them if need be; every thread unregisters itself when it completes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant