Disclaimer: This proposal was initially posted on #absinthe-graphql on Elixir slack. I’m reposting it here so that it doesn’t get buried.
Some time ago on Slack, I have asked about ETS memory usage in the context of Absinthe subscriptions and possible improvements. Unfortunately, the related threads are long gone from Slack (I recall I was discussing it shortly with @benwilson512 at the time).
Anyways, I’ve recently circled back to it and came up with a potential improvement with a minimal impact on CPU. Here’s the proposed patch:
Instead of storing precomputed
initial_phases where options (along with context) are repeated several times over, we are storing just enough information to reconstruct them using
Absinthe.Pipeline.for_document/2 which comes down to building a list of phases with options put in a number of spots, which should not be computationally expensive.
If I haven’t missed anything obvious, that change should be transparent and non-breaking
I have run a series of simple tests with absinthe’s test suite as well as test suite of a larger app I’m working on that uses subscriptions extensively. For the purpose of the experiment I have added a line calculating byte size of a serialized map stored in elixir registry by
Absinthe.Subscriptions.subscribe, like this:
doc_value |> :erlang.term_to_binary() |> byte_size() |> IO.inspect(label: :PAYLOAD)
This is not the same amount of space it takes up in ETS memory but it gives an idea in relative terms. Then I have run tests for both absinthe and the app without and with the patch applied. Here are the results:
As can be seen, the memory usage can be lowered even >10x this way. Given, in our case, roughly ~90% of VM memory in production is taken up by those ETS entries for subscriptions (multiple subscriptions per user), that would substantially lower memory usage. What do you think?
UPDATE: Here’s one more round of test runs against our app where the sum of memory occupied by the ETS tables for key partitions is checked (10648 is subtracted from each table because that seems to be the base size on this particular setup):