Earlier quoted context omitted.
Oh that's so funny, because I'm an elixir user and we all claim that genserver (internal) organization is terrible. But yes, it is way better than callback hell... It just could be better still.
not genserver, what will you use?
Elixir GenServer Explained
81–90 of 91 posts
Re: Elixir GenServer Explained
#82Earlier quoted context omitted.
Oh that's so funny, because I'm an elixir user and we all claim that genserver (internal) organization is terrible. But yes, it is way better than callback hell... It just could be better still.
not genserver, what will you use?
That said you shouldn't write genservers if you can help it. Using the frameworks genservers Is the best choice, Task is a better choice for most cases.
Re: Elixir GenServer Explained
#83Re: Elixir GenServer Explained
#84Thank you so much for sharing this. I've not yet finished a decade in the industry, nor ever laid an eye on Elixir before, and this made sense pretty quickly. Great job explaining it all! On a side note, its pretty amazing to see the impact on readability and understanding that native language features have on something like async. I've worked with similar systems to the example in the past in JS/Go/etc, and while yo…
Re: Elixir GenServer Explained
#85Earlier quoted context omitted.
It flows better because it is writing synchronous code. The code inside of every process in Erlang is synchronous. You achieve concurrency by spinning up processes (spawning functions). This isn't that different to firing an async function in Javascript, or starting a goroutine, etc. And you communicate between the processes by sending async messages. Those are the primitives. Asynchronously send messages between pro…
The formal framework for this is called CSP ("Communicating sequential processes"). I discovered this 15 years ago, and once you understand it, you will never have problems in multithreading again. https://arild.github.io/csp-presentation/#3
Re: Elixir GenServer Explained
#86Since these insert events are being buffered, what happens if the process dies? Are all of those inserts lost? I feel like Erlang/Elixir is designed to handle cases like this robustly, but it's not clear to me how this code avoids losing data when a process crashes, potentially up to 5s worth of updates!
So for example one possible implementation of state is that you catch your own crash, save some state and then restore it when you restart
You aren't supposed to ever crash, however the whole language it's based around designing a framework to handle what happens if you do crash
So you design a whole framework of supervisors, watching processes, that all have a defined startup and shutdown order. You build structures with rules such as: if my cache module fails, them restart this whole chunk of application over here.
it's very cool
Re: Elixir GenServer Explained
#87Earlier quoted context omitted.
The formal framework for this is called CSP ("Communicating sequential processes"). I discovered this 15 years ago, and once you understand it, you will never have problems in multithreading again. https://arild.github.io/csp-presentation/#3
Not exactly. CSP is more what Golang adheres to (synchronous communication). The Actor Model predates CSP. And understanding it you'll still have problems...they're just different problems. You either won't be able to use a language with message passing as a concurrency primitive (i.e., almost all popular languages other than Go at this point), or you will, and now you'll have the time to spend on new types of proble…
Re: Elixir GenServer Explained
#88It is very interesting to me that components in OTP like GenServer, Register, and Supervisor are surprisingly intuitive if one tries to learn and play Erlang first, but not so obvious and possibly looks artificial if people don't learn Erlang in the first place. At first, I was surprised that the Erlang processes resemble the Actor model in such a minimalistic interface. Then I play with them for a while, I realized…
"Any sufficiently complicated concurrent program in another language contains an ad hoc informally-specified bug-ridden slow implementation of half of Erlang."
Erlang's been around long enough at this point that for pretty much any problem in Erlang's area of expertice you find yourself solving twice, there's a damn good existing solution somewhere in the OTP.
Re: Elixir GenServer Explained
#89Maybe a dumb complaint, but I hate the name. I have a really hard time not reading it as the active name "Generate Server". Like, I'd expect it to be a function that generates servers (whatever that means, since what it's dealing with isn't something I'd normally call "a server" either). It bugs the hell out of me every time I read Elixir code. One of those things I have to keep reminding myself: "OK, it's not what i…
It's a terrible name, anything starting with the abbreviated prefix "Gen" is hopelessly ambiguous. Is it "Generate"? "General"? "Generic"? "Genetic"? "Genesis"? While some would certainly be less frequently encountered, all can easily be found in programming context. When seeing "GenXxxxx" I could well understand someone feeling immediate brain-fog. That said, this is one of very few criticisms I can level at Elixir,…
alias GenServer, as: GenericServer
Done.
Re: Elixir GenServer Explained
#90Earlier quoted context omitted.
Not exactly. CSP is more what Golang adheres to (synchronous communication). The Actor Model predates CSP. And understanding it you'll still have problems...they're just different problems. You either won't be able to use a language with message passing as a concurrency primitive (i.e., almost all popular languages other than Go at this point), or you will, and now you'll have the time to spend on new types of proble…
The nice thing about the cleanly independent processes is that by and large, "let that part crash, and keep going" is a perfectly adequate answer to most process states outside the pretty path, which is a real saving grace when working with wildly concurrent systems.
On this particular distinction, in fact, it's one of the benefits the actor model has over CSP. In the actor model (well, Erlang's take on it, but that's one that has been adopted elsewhere such as in Akka), I care about "if this fails, who should be affected by it". I.e., by default, it's just this process, and with a supervisor it'll restart. How do I get it restarting into a good state? If it goes down, who else needs to go down (to keep state consistent)? That's mostly all I have to ask myself; I don't have to ask what all the ways it could go down are (slight caveat there; you still want circuit breakers around external resources).
With CSP, I have to ask "if this goes down, who else IS affected by it". Not who should be, and be intentional about linking them, but determine who accidentally is affected by it. This is everyone who might be sending or receiving across a channel (to borrow Go parlance) this process has access to. Which breaks the abstraction; from the perspective of the current process I shouldn't have to know who is sending or receiving across a channel, but the reality is I -do-. And that's no better than the error model I have in other languages; I have to understand every part of my application to know what may or may not be affected by this one part going down. Go gets 'around' this by just making it so any uncaught exception (err, unrecovered panic) crashes the whole application, which is certainly one way to do it.