3 ms·
This is very good feedback and show flaws in areas that could be improved. Thank you! I will add some comments below but they are not meant to dispute your cla
by josevalim 9y ago
This is very good feedback and show flaws in areas that could be improved. Thank you!
I will add some comments below but they are not meant to dispute your claims but to find places where we can improve.
> The log messages suck. If I want to use them in production and actually ship them to ELK or similar, the format really sucks.
Do you mean the Logger messages? Their format is customizable. Can we make this clearer?
> Getting information on what happens at compile time vs run time is hard.
Which kind of information do you need? Is it something that would fit the meta-programming guide on the website? Or maybe we are missing a more detailed compiler guide?
> 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.
It was not possible cleanly until OTP 20, so it is fairly new. At least, from 19.x onwards, the VM will shutdown cleanly on SIGTERM - which means shutting down all applications and supervision trees. A lot of guides (including the Elixir guides) cover supervisor only through the fault tolerance perspective, while they also encapsulate the start-up and shutdown logic. I have opened an issue for this here: https://github.com/elixir-lang/elixir/issues/6479 https://github.com/elixir-lang/elixir/issues/6479
> 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?
Running your code is a matter of starting your application. We don't really have a `main` procedure as an entry point. Your system is designed as a series of applications and you start them. If you are using mix, it should be a matter of `mix run --no-halt`. If you are using releases, it automatically starts the system for you. Where would you expect to find this information? Did you see `mix run` at all? Maybe in the escripts page we should point to `mix run` as it seems an `escript` is really not required in your case?
> 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.
Those particular error message were fixed in Elixir v1.5 (with OTP 20+). Pull request is here: https://github.com/elixir-lang/elixir/pull/6127 https://github.com/elixir-lang/elixir/pull/6127
> Flow / Genstage and getting them into a supervision tree? what's the best practices.
Please open up an issue. If this is not clear form the documentation, it is a "bug" in the docs.
It is also worth mentioning that Ben Marx, Bruce Tate and I are working on book called "Adopting Elixir"
(https://pragprog.com/book/tvmelixir/adopting-elixir https://pragprog.com/book/tvmelixir/adopting-elixir). The last three chapters focus exclusively on production aspects and it answers many of the questions here (log configuration, system termination, how to run it, design, etc).
- anko 9y agoJosé, thanks for taking the time to respond to my somewhat rambling comment. To be honest, if I had a clear idea on how to solve some of these things I would have done it - but i'm still a novice at the otp ecosystem in general. Maybe it's easier for me to walk through what I do, so I can show you where I run into problems. One of my favourite ways to learn a new language is in a REPL. I've used a lot of them in the past, and iex is pretty good. Pry (in ruby) is probably the gold standard. Interactive Elixir (1.5.0) - press Ctrl+C to exit (type h() ENTER for help) iex(1)> 1 / 0 ** (ArithmeticError) bad argument in arithmetic expression :erlang./(1, 0) This is pretty good. Now we can move on to pry [1] pry(main)> 1 / 0 ZeroDivisionError: divided by 0 from (pry):1:in `/' The beauty here is it's saying the same thing, but the information is slightly more precise and it tells me clearly that the function being executed came from (pry) which makes a load of sense to someone using pry. I know this is a basic example, but in elixir, as you start spawning more and more processes, deciphering the log messages gets harder. back to iex Task.async(fn -> 1 / 0 end) ** (EXIT from #PID<0.94.0>) evaluator process exited with reason: an exception was raised: ** (ArithmeticError) bad argument in arithmetic expression :erlang./(1, 0) (elixir) lib/task/supervised.ex:85: Task.Supervised.do_apply/2 (elixir) lib/task/supervised.ex:36: Task.Supervised.reply/5 (stdlib) proc_lib.erl:247: :proc_lib.init_p_do_apply/3 07:34:45.847 [error] Task #PID<0.97.0> started from #PID<0.94.0> terminating ** (ArithmeticError) bad argument in arithmetic expression :erlang./(1, 0) (elixir) lib/task/supervised.ex:85: Task.Supervised.do_apply/2 (elixir) lib/task/supervised.ex:36: Task.Supervised.reply/5 (stdlib) proc_lib.erl:247: :proc_lib.init_p_do_apply/3 Function: #Function<20.99386804/0 in :erl_eval.expr/5> Args: [] This is scary. Why's it repeated? why does one have a timestamp? how does "lib/task/supervised.ex:85: Task.Supervised.do_apply/2" get here ? I called Task.async which doesn't show in the messages? I want to reiterate at this point that it's not that bad, I think the repl is pretty good but the error messages just leave a bit to be desired. Maybe there is an article on deciphering them? But if you need that, I'll say it's a barrier. In terms of the formatter, I need to go through my old code to remember where all those particular hurdles were, but someone has suggested a prebuilt json formatting logger which sounds good to me. A sweet spot for Elixir (for me) is queue processing, in an autoscale group on AWS. So I have a real application in mind, and I originally knocked it up with hardly any knowledge and using genstage for back-pressure etc. in a couple of nights. This is saying a great thing about the language. But then shipping logs, deployment, debugging (if i deploy with distillery it locks up, and it has slow memory leak that makes no sense to me), dockerising, handling autoscale events have all stopped it from going to production ready. > Where would you expect to find this information? Did you see `mix run` at all? Maybe in the escripts page we should point to `mix run` as it seems an `escript` is really not required in your case? A guide on https://elixir-lang.org/getting-started/introduction.html https://elixir-lang.org/getting-started/introduction.html would be great, to just give the different options and when you'd use them. Maybe something like "The anatomy of an elixir application" (or program because application is overloaded). For me it is the cyclic journey through the different ways to do things. So it took a while to work out that I can't just pass in command line parameters to mix run, so the application gets them. Unless i'm wrong? In escripts I can. And they will start the application automatically. Why would I use them? And what's the difference between them and running mix run lib/script.exs? So then I started thinking - maybe the ideal way is to have an application running in the --no-halt way like you've described and have an escript connect to it to pass in configuration changes. But i'm just hacking different ways rather than learning from an example or best practice. I'd love config to be changeable on the fly for a daemon / application. > Which kind of information do you need? (re: run time vs compile time) in my limited experience, config.exs pulls in config params at compile time. I thought it would happen at run time because it's a script (exs). I know phoenix has a way of dealing with this, but i haven't gone fully down that rabbit hole yet, because I'm not even sure if config.exs is right for my requirements. If I want it to be hot loaded, I'm thinking I need a genserver with the config as its state, and some way to communicate changes to it - either from the file system or an escript. > Those particular error message were fixed in Elixir v1.5 Thank you, it sounds like a great release I'll open that issue, and check out your new book too because I really think there are huge gaps between 1) I can write genservers and get that 2) I know the tradeoffs and best structure for my supervision tree (especially with things like OS signals thrown in the mix) 3) I can deploy this into production 4) 5) 6) I can leverage distributed features