GenServer.handle_continue/2 is OTP 21+ and there are still many users on 20-. One might simply spawn another process/task in do_init, if there is a need to initialize asynchronously.
Also, I am not sure there is the best strategy in what process should crash. Sometimes it should be GenServer and sometimes it should be its supervisor. I like the explicitness and callbacks are kinda magic; maybe I should reconsider my attitude, though.
You should definitely reconsider. Using the GenServer callbacks is the OTP way.
If you want the supervisor to crash when the GenServer crashes, that's what the "maximum restart intensity" is for (default 3 restarts in 5 seconds, configurable via max_restarts and max_intensity).
It's true that GenServer.handle_continue/2 is OTP 21+. The old practice was to use send(self(), :post_init) in the init callback to allow start_link to return while triggering some additional initialization (not to spawn a process). This was unfortunately also susceptible to the race condition that the process could receive another message before :post_init, if the process was named. So in OTP < 21, there is no good solution to this problem.
We're a place where coders share, stay up-to-date and grow their careers.
We strive for transparency and don't collect excess data.