[HN Gopher] Neat Elixir trick: Libraries can start processes too
       ___________________________________________________________________
        
       Neat Elixir trick: Libraries can start processes too
        
       Author : sandbags
       Score  : 28 points
       Date   : 2021-08-01 10:36 UTC (1 days ago)
        
 (HTM) web link (mattmower.com)
 (TXT) w3m dump (mattmower.com)
        
       | jolux wrote:
       | This is a huge part of the power of Elixir/Erlang. Libraries can
       | be written to use the same powers of isolation, resiliency, and
       | concurrency that application code has, at no extra cost to the
       | consumer and with total transparency.
       | 
       | You quickly realize that every function you call could be working
       | asynchronously underneath, and it's not scary because the whole
       | system is designed to function like this.
        
       | dceddia wrote:
       | In earlier versions of Elixir where you had to explicitly add the
       | libraries as additional processes to start, I remember being very
       | confused why things like e.g. an HTTP client needed its own
       | process. To be honest I still felt a little uneasy about it every
       | time. Thinking of those processes as just "the library needs some
       | internal state" makes so much more sense!
        
         | dnautics wrote:
         | Problem is, it's not entirely clear that an http client library
         | needs external state. (And for example, mint does not).
        
       | AlchemistCamp wrote:
       | Many, many libraries do this! It's a key feature.
       | 
       | (to clarify, these are light-weight _Elixir_ processes, not OS
       | processes)
        
       | dnautics wrote:
       | I really wish that in elixir we drew a distinction between
       | dependencies that do and don't spawn their own supervision trees.
       | It would be nice if this were reflected in, say, hex.pm, possibly
       | using different tags for them.
        
         | QuinnWilton wrote:
         | Agreed. I also wish fewer libraries started their own
         | supervision tree, and instead gave you a child spec to drop
         | into your supervision tree. There's definitely use-cases where
         | shipping libraries as an application makes sense, but
         | oftentimes that sort of design causes problems for me, because
         | it means not being able to start multiple copies of the
         | dependency with different configurations.
         | 
         | I think Phoenix PubSub is a perfect example of how libraries
         | should be structured, in that you just need to drop the module
         | + options into your supervision tree, and you have the freedom
         | of starting multiple independent copies of the tree, in
         | different contexts, and with their own configurations:
         | https://hexdocs.pm/phoenix_pubsub/Phoenix.PubSub.html#module...
        
           | jolux wrote:
           | You do sometimes have to be careful about how you handle
           | configuration with embedding multiple copies of other
           | supervision trees though:
           | https://ninenines.eu/docs/en/ranch/2.0/guide/embedded/
        
           | dnautics wrote:
           | I'm 50-50 on that one. This may be an overly nitpicky detail,
           | but I you sort of want your own sup tree to not _necessarily_
           | have a different-ly scoped  "microservice" tied to it in
           | terms of failure domains. For the 90% use case (e.g. http
           | process pools) an indepentent sup tree is correct, but to
           | your points,
           | 
           | 1. it would be nice to have a choice. The library-writer
           | should think about their users and choose which case is more
           | correct. And make it opt-out and easy (let's say 2-3 loc) to
           | implement the "other case", and spelled out explicitly in the
           | readme/docs landing page.
           | 
           | 2. PubSub indeed made (IMO) the correct choice when it
           | migrated over from being its own sup tree to moving into the
           | app's sup tree.
           | 
           | Thank you for listening to my TED talk.
        
         | lostcolony wrote:
         | It's not obvious from use? It's been a long time since I was in
         | this world (well, Erlang), but it was
         | application:ensure_started(App) that let me know "this
         | dependency has its own supervision tree".
        
           | dnautics wrote:
           | Httpoison, for example, starts its own supervision tree to
           | manage client process pools (not obvious that an http client
           | should do that, definitely usecases where it shouldn't) and
           | there is no indication either in mix.exs, or
           | `MyApplication.Application.start/2` that Httpoison needs the
           | tree. For most deployments, it's probably not a big deal.
           | Some process will try to read http content, fail if httpoison
           | isn't quite ready, and be restarted by its supervisor.
           | 
           | However, if you try to use it early in compilation or test,
           | say, in your test_helper.exs file, speaking from experience,
           | you could wind up with a very difficult to understand race
           | condition where the httpoison process tree hasn't fully
           | booted and you're trying to fetch something off the internet,
           | and you don't have the same level of supervision protection
           | -- if test_helper fails the whole test suite gives up and
           | doesn't restart -- for obvious reason.
           | 
           | For the http case thankfully the elixir ecosystem is getting
           | Mint as a base http library, which doesn't require a process
           | tree out the gate, and several interesting explicit process-
           | pool-libaries (finch, mojito) which are tuned for their own
           | use cases that derive from mint.
        
       | OskarS wrote:
       | I think Erlang and Elixir are incredible, and this particular
       | feature of libraries starting BEAM processes seems cool in the
       | abstract. However, this PARTICULAR task, Erlang/Elixir might be
       | the worst possible language you could choose:
       | 
       | > _The Elixir approach to shared mutable state is wrapping it in
       | a process. In this case, I needed a counter and the easiest way
       | to implement it is to use an Agent which is a kind of process
       | designed to handle simple state. In this case, the get_and_update
       | function allows me to return the counter and increment it as an
       | atomic operation._
       | 
       | This is literally just an atomic counter. It's a single CPU
       | instruction that is guaranteed to be safe. I don't care how
       | lightweight a BEAM process is, it's not faster than updating an
       | atomic counter. Doing it this way is also absurdly more
       | complicated than using, say, a std::atomic in C++ (or the
       | equivalent type in other languages).
       | 
       | Again, I think Elixir is cool, but if you want to show off how
       | cool it is, maybe don't use an example that is incredibly much
       | slower and more complicated than it should be. It's not a great
       | look for Elixir.
        
         | enjo wrote:
         | Of course you're right, but I think anyone who is capable of
         | getting their head around Elixir is capable of understanding
         | that this is a trivial example meant to showcase a powerful
         | language feature. What you choose to use it for is up to you,
         | not the article's author.
        
           | OskarS wrote:
           | I see that point, but it was pretty jarring reading this
           | Elixir article as a curious outsider that they had to make
           | these kinds of very advanced contortions to do something so
           | simple in such a non-performant way. It's something that is
           | only impressive if you were already totally sold in on the
           | BEAM way of doing things, but looks insane to any
           | C/C++/Rust/Java/whatever developer.
        
         | whalesalad wrote:
         | Processes on the BEAM may not be on the same machine or even in
         | the same datacenter. You can't assume that everyone has access
         | to the same physical memory.
        
       ___________________________________________________________________
       (page generated 2021-08-02 23:01 UTC)