One question that left me scratching my head: How were you able to get a GenServer named with a binary? Typically names are only allowed to be atoms, {:global, term}, or {:via, module, term}.
I feel like there’s something unidiomatic going on under the hood which is causing these issues. If you don’t mind a few suggestions:
- Unless you have a really really really good reason to, you should typically be launching a GenServer from a function with the
startorstart_linkof its own module. You might not do it if you have some sort of abstraction generator (I really don’t want to say “factory”, because, yuck). - Whether or not it’s coming from its own module, Conventionally a
startorstart_linkfunction should probably output something that looks like{:ok, pid}, which you can then use to do yourGenServer.cast/calls - Generally my rule of thumb is “you shouldn’t be using
GenServer.castunless you really know what you’re doing”. as you see herecasts will silently fail; ifcalltimes out or drops an error, that might be saying something about your plans. When you deploy to prod, a failing call will be quite noisy and so you can track those and fix your code (or not, if it’s rare/innocuous/expected enough not be worth the effort) - GenServers are fundamentally an async- sort of thing, so wrapping a spawning a GenServer inside a
Task.asyncin a test seems like a red flag; the test should probably be launching the GenServer itself. The pattern gives you a lot of power;startandstart_linkblock on the completion ofinit, and should contain bootstrapping bits that live in the calling process; andinitcontains the bootstrapping bits that live in the child process. If you need to unblock the caller early before bootstrapping is done, and some bootstrapping things on the child process’ time, you can issue a:continuedirective. There’s also tools likeConnectionlibrary for other special cases.
Not to be too prescriptive, but It seems like you should be able to refactor your modules to conform to these parameters.


















