Quite surprisingly, Supervisors do not have an exposed option for taking a spawn_opt
. spawn_opt
are process options that are used to control the process behaviour when it comes to memory management, and can be incredibly useful when hunting down garbage build-up in processes.
The Backstoryโ
This week in life at Supabase, we have some fun garbage collection optimization, and it mostly involves tweaking culprit process behaviours into clearing out their garbage in a timely manner.
Sometimes, garbage might build up as shown for a myriad of reasons, and we gotta take our massive major GC hammer to knock some sense into these processes that are stuck in a minor GC loop!
The Problemโ
So, Supervisors don't actually take a spawn_opt
, so after digging around, the only real option was to use the :erlang.process_flag/3
function, which is wrapped by Process.flag/2
.
We can achieve the the :fullsweep_after
tweaking as so:
def init(_arg) do
# trigger major GC after 5,000 minor GCs
Process.flag(:fullsweep_after, 5_000)
...
end
One would think that it would be accepted by Supervisor.start_link/2
, but it seems like it isn't at all, and I had to dig into the Elixir source code to find that out.
A Word on Task.Supervisorโ
Although the base Supervisor module doesn't accept the :spawn_opt
option for its start_link/2
callback, the Task.Supervisor
built-in module does accept it.
This can be see here where there is an explicit test case for this option passing.
Quite an interesting tidbit ๐