I really am in awe of Elixir. I think it's an amazing language, and it introduced me to Erlang and OTP. I've come from using scala actors, and I can do more in way less time, less memory, and similar performance if I use Elixir.
That said, there are some things that suck so hard about it.
The log messages suck. If I want to use them in production and actually ship them to ELK or similar, the format really sucks.
Getting information on what happens at compile time vs run time is hard.
How do you handle operating system signals? like when your autoscale group decides to scala down and you get a SIGTERM with some time to handle it, what do you do? wrapper scripts suck.
Not many great design resources.. I mean I've got lots of books on OTP. But if i'm building a daemon which reads off a queue and talks to some databases - where are some patterns I can follow? How do I handle config? What if I want to hotload it?
What command do I run? when do I run an app vs compiling it? What If I want command line args? Where's a good example of writing an app, which is a daemon, and using an escript to reconfigure it at runtime?
The error messages. Holy hell. What actually caused a pattern match to not work? what is it expecting? especially a few function calls deep - like interaction between tuples and arrays and keyword lists.
Flow / Genstage and getting them into a supervision tree? what's the best practices.
I want to introduce it to my workplace but without some of these common patterns easy to find, it's kind of a risk to the business.
This is a fair point, even in Erlang land. There are a zillion things encouraging you to "let it crash" and far fewer going beyond that.
One thing that doesn't get mentioned often enough is a circuit-breaker like fuse: https://github.com/jlouis/fuse
This also has some more advanced topics: