Which companies are using Erlang, and why?
erlang-solutions.com
erlang-solutions.com
Erlang is nice enough language and I don't mind the syntax but it's also kinda cumbersome and verbose at times. For example, adding `true -> ok` to every if statement gets old fast. Similarly, Erlang/OPT is a nice platform but some parts are fairly bad. Looking at you `inets/httpc`.
But the really big problem was the whole ecosystem. Build process was needlessly complicated. Surprisingly enough multicore support was not great. Performance was not that great. It seemed like a lot of libraries were abandoned after 2013. I could go on.
We ended up rewriting the whole thing in Java and, so far, it worked out great. And after Java 8, Java the language is not so bad. I still have somewhat found memories of Erlang but I don't miss it.
We were handling, in peek hours, over 100k requests per second spread over 3 servers.
Funny you should mention scalability as something that somehow justifies Erlang's other shortcomings. I don't think scalability is something Erlang/OTP does out of the bag. One thing we learned the hard way is that Erlang does not do overload well at all. Erlang mailboxes are unbounded and it can get very messy very fast. I always found that design choice odd given Erlang's origins in telecommunications.
Now this is not to say you can't do massively scalable systems in Erlang, it's just that there's no silver bullet when it comes to scalability.
How big was one server and what does one request entail?
You can get just about anything to "scale" given architectural compensations (like scads of containers), so this, ipso facto, doesn't mean much.
> so why not use a language that's nicer to work with?
Well, why not indeed? But here are some thoughts about that.
Nothing is a panacea, Erlang included. Some of the ecosystem is ugly and hard to work with, but improving. Erlang is in a vicious cycle:
* Erlang ecosystem sucks
* Fewer people want to use it
* Fewer people are available to improve the ecosystem
* Fewer people are available to fill jobs for Erlang
* Less demand for Erlang
* Loop
Erlang gives you certain things that no other language I know of does, and these things make it a more robust, easier to program, highly concurrent solution without needing architectural compensations for those things.
That doesn't mean that you can magically throw 1 million TPS at Erlang running on N boxes and your internal queues/mailboxes won't overflow. You, along with the rest of the world, need backpressure handling mechanisms.
What Erlang gives you that Java doesn't is totally decoupled processes that cannot directly affect each other. No mutexes or semaphores, no shared global memory.
It also gives you ultra-lightweight processes that garbage-collect independently of each other, that are cheap enough to start and stop that you can create one per incoming connection and make it completely unaffected by any trouble that any other process gets into. This is not true of threads in Java.
It gives you a supervisory framework that, if used judiciously (yeah, yeah, no true Scotsman, but that doesn't make this any less valid) gives you an ultra-robust system that degrades gracefully under error or overload conditions.
It gives you linked processes that detect a broken process and brings down the others (if you so choose) to avoid leaving orphaned processes cluttering up the system, plus automatic restart, baked in. These do come free of charge when using OTP supervisory frameworks in the recommended fashion.
I think that in some cases, Erlang has been overhyped and people come into it expecting it to magically solve all the hard problems. People that overhype Erlang do it a disservice. For example, the stupid "nine nines" thing was an almost once-off, limited situation in a very constrained environment and I am sure many Erlangists wish it had never been mentioned.
And I wish nobody had ever said the words "let it crash", because they have been misunderstood and taken out of context and again done Erlang a disservice. Just like the phrase "premature optimization is the root of all evil" has caused untold damage when it was (and is often) taken out of context.
The whole "let it crash" thing was shorthand for "if a process cannot reasonably handle and error condition itself, let it die and be reincarnated by the supervisory process". It does not mean "just let everything crash". For example, if you have a system that has long-lived connections, maybe (say) http/2 connections, or XMPP, or Apple push, you most definitely do not want to let it crash without doing everything possible to recover from errors such that the connection stays up under as many error conditions as possible.
But for the most part, a process should not be written defensively and try to recover from errors where it has no business doing so - it should leave it to the supervisor.
I have written Erlang systems, heavily used in production that ran reliably, without crashing, for many months. Usually they were only stopped to do an OS upgrade. They weren't error-free - we found out about some persistent errors by checking the logs occasionally, then fix them and often hot-patch the fix into the production systems.
Again, Erlang is not the world's best programming language or ecosystem. It is, within its design envelope, one of the finest soft real-time distributed multiprocessing environments around when used, like anything, with skill and careful architectural design.
In my humble opinion.
I don't know of any system, stack that handles it directly, natively. Though my sample size is pretty small.
1. If-statementes should rarely be used in Erlang because case is preferred
2. If you're returning ok everywhere, you could also just let it crash by doing something akin to true = function(). Always go for let it crash first, unless you really know you can handle the error sensibly (and then use a case-statement)
3. httpc is kind of known to not be the most formidable HTTP client. Hackney is a more modern and better choice. The good thing with httpc is that it is included with OTP, otherwise there are better choices (scalability- and feature-wise)
4. When someone says "multicore support" and "performance" support is not great it's usually one of two things: (a) they're developing a use case that is not fit for Erlang (e.g. compute heavy) or (b) they don't know how to use Erlang properly (e.g. too complex process setups)
Now, many of these things are not obvious to people new to Erlang and takes some experience to know about. This I would say is the bigger problem with the Erlang eco-system.
(1) there are situations like this:
if
DeductCreditInRatingGroup ->
log("deducting credit...");
end;
unfortunately you cannot write it this way. You have to write it as: if
DeductCreditInRatingGroup ->
log("deducting credit...");
true -> ok
end;
Not a huge deal but it's annoying.(2) Let it crash attitude is something I never understood. It's just not something you can do most of the time. If subscriber consumed 2MB and you let it crash in the middle of rating function you just "lost" 2MB. With couple of million subscribers on LTE that turns into very expensive error handling very fast.
(3) We actually ended up using hackney.
(4) We were not doing anything compute heavy. I think our application was well architected and we had no problem fitting it into OTP "framework". Comparing CPU and memory usage to our Java implementation, Java is more performant.
edit: fixed code formatting.
log("deducting credit...", DeductCreditInRatingGroup),
...
log(Msg, true) -> do_the_logging();
log(Msg, false) -> ok.
Nowadays though, you should really use the new logger introduced in Erlang 21. There you can do run-time filtering on many different parameters, or even write your own handlers. Using if-statements is usually considered an anti-pattern in Erlang, and I think very common coming from languages where only if-statements exist. Problems are almost always better solved by using case, or even better, pattern matching in function heads.2. Sounds like one of the rare cases where you care about the error and can also handle it. In the use case you mentioned, I would buffer the data outside of the loop that produces it and wrap the loop in a try-catch statement. That way, you don't loose the data if one iteration crashes.
4. Erlang usually ends up being good at latency and concurrency (scalability over cores), together with a smaller and easier to read code base. I'm curious about your case, and what would have made Java a better fit. If you share a lot of global objects, Java might be faster for some things (at the cost of concurrency usually). Erlang has tools for that as well though (e.g. ETS and recently persistent_term).
(2) I would argue that it's a rare case you don't care about errors.
(4) Multicore support in Erlang was not always great and you would run into all kinds of problems after 2-4 cores. Than for a while it was 12-16 cores. Not sure what the limit is these days.
Again, I am not arguing Java over Erlang. There is no lack of great examples of large successful project running on Erlang. For me and my team Erlang was just too much hassle for not much gain. Your milage may vary.
You always care about exceptions/errors. The thing is, most you won't predict/can't handle. Those you do predict, and know how to handle, you should, because they're not really errors/exceptions at that point; they're just edge cases.
The point of Erlang is not to make it so you just throw instead of addressing an edge case; it's to make it so you reason about how, if something you don't predict and don't know how to handle happens, you can get back into a known good state. It's actually phenomenal at doing that. I've had complicated user facing production systems work without noticeable issue for years (even while under active development) in Erlang. I've never seen that in any other language. Not to say it can't happen, I just haven't seen it, and the operational lift to achieve that was no different for us than just "make it work"; we were spending the same amount of time thinking about failure cases with the Erlang system as other languages. The difference was a better approach to handling the things we didn't think of.
2. In Erlang it usually only make sense to care about errors which you can actually handle in a sensible way. Everything else you usually "let crash" and let the supervisor tree deal with recovering. Defensive programming is another anti-pattern in Erlang in my opinion.
4. Not sure what you mean with "not great". With Erlang, if you have a completely parallelizable problem you should see close to linear scalability. If it drops of after that it's either because the problem is not parallelizable enough or because of your architecture.
Yeah, I'm not arguing Erlang over Java either. I'm just pointing out that blanket statements like this are usually because of architecture or design rather than shortcomings of the language itself.
Let it crash is the only sensible thing to do. Depending on the type of error, the 2MB could be absolute garbage. I would rather stop sending any message instead of sending potential wrong data without knowing.
DeductCreditInRatingGroup andalso log("blah")
2) Let it crash attitude is often misinterpreted. It means your system should be fault-tolerant in general, so you can focus on the happy case instead of trying to predict all humanly possible failure modes. If you _expect_ invalid input, then handle it properly.And it in terms of performance it indeed require some design experience on Erlang process. But it shouldn't be bad. After all WhatsApp and Discord have run on top of it with very few engineers to support massive customers before. I doubt online charging system could be more chatty.
it regularly tops performance benchmarks - https://www.techempower.com/benchmarks/#section=data-r18&hw=... and super simple heroku deployments - https://github.com/vert-x3/vertx-examples/tree/master/heroku...
Also Kotlin !! https://vertx.io/docs/vertx-core/kotlin/ (kotlin vertx on heroku: https://github.com/vert-x3/vertx-examples/tree/master/kotlin...)
10 years ago the ecosystem was horrendous, and is much better now. Granted, the build experience could be better but I didn't find it that bad.
I find that people's experiences are relative to what they are accustomed to. Early years for me included compiling and linking C in Windows (segmented) and that was truly horrible!
If you want the obvious explanation, it's because we all have different experiences, and no one tool will be the biggest win for all teams across all domains.
Considering that it’s state of the art, you must have been doing it terribly wrong.
> adding `true -> ok` to every if statement
That confirms it.
Today’s Erlang (R22) MP support is practically the best, bar none.
This makes it easy to generate code on compile time, which is then executed in runtime without any performance penalty.
A large part of Elixir itself is actually implemented as macros. For instance, the "unless" construct:
defmacro unless(condition, do: do_clause, else: else_clause) do
quote do
if(unquote(condition), do: unquote(else_clause), else: unquote(do_clause))
end
end
(code simplified for clarity)The Supervisor system, the per process garbage collection (no stop the world), 'start_link', "Let it crash", and pattern matching are for me the superpowers of beam. Elixir is contributing a great package ecosystem, 'mix format', and better features for the new live web of websockets
> There is no better example of Erlang’s reliability than the English National Health Service (NHS). [...] Using Riak (written in Erlang), the NHS has managed 99.999% availability for over five years.
From what I could find out, NHS's Spine2 is mostly Python, with "a bit" of Erlang and Javascript. They do use Riak, but they also use Redis, RabbitMQ, Python/Tornado, Ubuntu and lots of other components.
This sentence could have said "Using redis (written in C)", or "Using Tornado (written in Python)", and still be fully correct.
This approach is pretty interesting - I’d love to read about implementing Erlang-style availability in other languages.
https://github.com/becls/swish
Another in Gambit Scheme, but it hasn't been touched in a while:
Really? I am not sure I trust this claim.
[1]: http://martinsumner.github.io/presentations/spine2_erlang#/2...
I'm biased in that I've been heavily involved in the project, but I will stand by the five years of five nines availability claim.
Some more info on riak.org about the current story regarding who maintains would help me a lot in choosing it.
To me Riak was the only noSQL scale-out-able data store product that really made sense.
- telecoms, as it was specifically designed for telecoms.
- "glue" in networked applications: to orchestrate, pass messages around and the like. See GitHub [1] or CoD [2] etc.
In a sense, chats are a mix of both. Erlang is rarely a good fit in pretty much anything else.
[1] https://www.infoq.com/interviews/erlang-and-github/
[2] https://www.erlang-factory.com/upload/presentations/395/Erla...
Like what ?
Probably because that claim makes no sense.
Do not assume you'll be able to build your own Whatsapp just because of Erlang.
The story is greatly underreported and all focus is only on "they run Whatsapp on Erlang with just ~50 engineers".
Highscalability lists just some of the patches and optimisations they have here [1] and here [2]
Here's an incomplete list of patches only. There's also tuning and optimisation:
Erlang: Fixed head-of-line blocking in async file IO by patching BEAM, added round-robin scheduling for async file IO, added multiple instrumentation patches. Instrumented scheduler to get utilization information, statistics for message queues, number of sleeps, send rates, message counts, etc. Made lock counting work for larger async thread counts. Patched to dial down spin counts so the scheduler wouldn’t spin.
BSD: Backported a TSE time counter. Backported igp network driver.
More Mnesia (Erlang) patches discussed here: [3]
Are you ready to do this for your Whatsapp?
> elixir/phoenix also achieved the same "2 million connections on single server" without needing those optimizations.
There's more needed to run a chat server than just "2 million empty connections".
---
[1] http://highscalability.com/blog/2014/2/26/the-whatsapp-archi...
[2] http://highscalability.com/blog/2014/3/31/how-whatsapp-grew-...
[3] https://www.infoq.com/presentations/whatsapp-scalability/
I don't need to thanks to the fact that a bunch of those patches are now part of Erlang.
There's also signinficant tuning and optimisation, both for the Erlang VM and FreeBSD.
There also things like (quotes from Highscalability):
"Mnesia: Using no transactions, but with remote replication ran into a backlog. Parallelized replication for each table to increase throughput."
"When Rick is going through all the changes that he made to get to 2 million connections a server it was mind numbing. Notice the immense amount of work that went into writing tools, running tests, backporting code, adding gobs of instrumentation to nearly every level of the stack, tuning the system, looking at traces, mucking with very low level details and just trying to understand everything. That’s what it takes to remove the bottlenecks in order to increase performance and scalability to extreme levels."
Or even the things like "What has hundreds of nodes, thousands of cores, hundreds of terabytes of RAM? The Erlang/FreeBSD-based server infrastructure at WhatsApp". Oh, wait. Erlang's default distribution mechanism grinds to a halt when there are more than ~60-80 nodes. And Mnesia has a 2GB limit on table sizes. So you have to work around those limitations yourself.
There are no magic bullets. Erlang will only take you so far. The rest (80-90% of the way) you have to take on your own, and you have to know what you're doing, and what needs to be done: patches, tuning, workarounds, limits of the systems you work with etc.
I've seen people say these, and I have no idea where they come from. If you have a decent network, dist works fine at well over 80 nodes, but everyone says it doesn't work. pg2/global has some sharp edges if you're trying to have many nodes acquire the same global lock when you have a lot of nodes (a few hundred) or a smaller number if you have a lot of latency between them. There's options though -- maybe you don't need to acquire the same lock on all nodes, or maybe you can look in pg2.erl and global.erl and wiggle the locking code until it no longer live locks.
The Mnesia supposed 2GB limit is a bunch of hooey. Yes, disc_only_tables has (or had) that limit, because dets has that limit. Yes, it's a sharp edge, because there's no warning about it. However, a 2GB dets table is awful to work with anyway. You want to use disc_copies or ram_copies for big tables. Also, mnesia_frag is well supported, so if you really wanted to, you could make your disc_only_copies table 1024 fragments, and have 2 TB of dets, if that's how you wanted to role.
And yes, if you're going to hyperscale, you're going to need a couple people who know how to figure out what your system is doing. Is there a language/environment where that's not true?
I claim, without real proof, that Erlang's BEAM VM and OTP standard library are easier to understand and tweak when you do hit problems. You'll note however, that Rick Reed's first presentation was when he had been at WhatsApp for about a year, and he had zero experience with Erlang before that.
You have a very naive view of large-scale distributed systems. For companies that truly need them, "time" and "effort" are never a consideration. Furthermore, the challenges facing these companies in battling project delays and cost overruns are the 100% organizational and political, not technical.
My entire intention was to say Erlang is easy to get off the ground with quickly.
Most companies outside of the Silicon valley bubble are resource limited.
a) Erlang (as opposed to something else) is only useful for large distributed systems.
b) If your organization is at the scale where you need a large distributed system, then the problems in your project aren't related to code or to coding speed.
b) Needing a large distributed system is a requirement that one can get to from lots of situations. You are making way too large of a generalization.
b) No. Large distributed systems is not something you stumble onto, it's a result of many years of organic growth.
I'm not sure that's true. Sure, a few of the most famous software companies in the world have built their own at considerable cost. But numerous other huge, important companies are dependent on large-scale distributed systems whose major drawbacks (reliability and maximum scale, usually) and major benefits (simplicity, time/resources saved on not having to hire tons of specialists, quick development time) are based precisely in the time and effort constraints under which those systems were developed.
In my mind, Erlang excels in a few ways:
Less often remarked, binary parsing in Erlang is rather nice. Parsing out an IPv4 packet looks like this:
<<4:4, IHL:4, _DSCP:6, _ECN:2, _TotalLength:16,
_Id:16, 0:1, _DF:1, MF:1, FragmentOffset:13,
_TTL:8, Protocol:8, _IPChksum:16,
SrcIP:4/binary, DestIP:4/binary, IPRest/binary>> = Payload,
OptsSize = (IHL - 5) * 4,
<<_IPOptions:OptsSize/binary, IPPayload/binary>> = IPRest,
And then you've got everything. As long as formats are reasonably documented, it's easy to parse them. Sometimes, you can even parse a size and use the size in the same match.More often remarked; because of the language constraints, most notably a lack of shared memory between processes and immutable variables, most programming ideas end up expressed in a way that's amenable to massive concurrency, while being comprehensible. Most Actors have easy to understand behavior --- they may accept messages, leading to them sending messages and changing their internal state. From there, you may need to puzzle out the overall system behavior, but often times, getting each individual Actor's behavior correct, leads to correct (if hard to verify) system behavior.
Hot loading code reduces deployment time, which increases developer productivity. When you've got a million users connected to a machine, it takes a lot of time to move them to other machines so you can do a traditional stop / start cycle; hot loading means you can fix things in seconds (and, of course, it means you can break things in seconds too). You can, of course, hotload in C, and probably other languages, but very few people do it. It's comparable to pushing PHP files though.
And, of course, the most important thing is ejabberd is in Erlang, and it looks like it has what we need for a chat server, and I heard some other people scaled it really far. ;)
It's because it's not super easy to properly architect in, it's hard to test, and it requires supporting running multiple versions of the code concurrently (and the ability to migrate data on the fly).
Keep in mind that we rolled out the patch incrementally to one or two machines and then to more. If it looked good we’d roll it out to the rest of the cluster. From there we’d make note of the result and get the change ported into a proper release.
Each time I hear stories that both clustering and hot upgrades, module loading, etc are hard or rarely used I wonder if the person is just repeating someone else’s rumor. They’re great features and work fine if you do a little homework (just like learning anything, don’t treat it like magic).
This was from my time at Cloudant/IBM, though its far from the only case I’ve seen. We ran over 1000 machines this way with some clusters growing to more than 200 nodes using distributed Erlang (something I keep hearing is hard or impossible, it’s not).
Badfun errors are a great example of something tricky if you're not used to thinking about how the compiler translates these to private functions via lambda lifting. It's the same reason funs are not something you should rush to pass around over a disterl cluster. Recursive functions which keep fun's around in a loop also become a problem if they're long lived.
I usually point out that first class modules or MFA tuples are more idiomatic in Erlang than opaque first class functions as values but we're off into the weeds here. It's a good example of where effort and gotchas become a barrier for many.
Lots of languages have actor systems. But how many have preemptive multi-tasking on these actor systems? I can't think of any at the moment. I am well versed in Akka for Scala and the lack of preemptive multi-tasking for actors is a big pain in the ass. Erlang's advanced BEAM and support for this is it's main selling point, imo.
For some tasks (scientific computing, UIs, offline analytics) Erlang might not be the best choice. However, within its domain of applications, it really shines.
A relational/object hybrid data model that is suitable for telecommunications applications. A DBMS query language, Query List Comprehension (QLC) as an add-on library. Persistence. Tables can be coherently kept on disc and in the main memory. Replication. Tables can be replicated at several nodes. Atomic transactions. A series of table manipulation operations can be grouped into a single atomic transaction. Location transparency. Programs can be written without knowledge of the actual data location. Extremely fast real-time data searches. Schema manipulation routines. The DBMS can be reconfigured at runtime without stopping the system.
I've found some practical aspects a bit painful though. It took me a while to figure out how to make backups, migrate schemas to different sets of nodes, that sort of thing. Also there are size limits on disk-based tables which are a bit limiting, and while you can use table fragmentation to get around that to some extent it doesn't seem straightforward to use (I haven't dared so far). I also don't like the way it deals with netsplits - when nodes reconnect it tends to require manual action to resolve.
There's now mnesia on leveldb
I actually prefer it. Too often systems out there don't tell you what they do in the event of a netsplit. They may have marketing copy somewhere that tells you what they try to do, but then you see the Jepsen tests and realize that's a lie, or is naive, or whatever.
Mnesia makes no secrets about it. In the event of a partition it stays partitioned, operating as separate nodes. It's up to you to figure out what to do about that. You can grab a Raft implementation to perform leader election, with the tradeoffs that entails. You want it to self-heal and deconflict based on arbitrary logic, for an eventually consistent system? You can do that too. You want to pretend it doesn't happen, stick your fingers in your ears, "LALALALA" until it does and requires manual intervention? That's fine too! What it DOESN'T do is give you a false sense of security while handwaving away the decisions and implementation concerns that were made to determine CAP behavior, which I find pretty much every other distributed data store does.
It definitely has pain points in learning it, and it also has some very definite limitations, but as a baked in, minimally biased distributed store, it's a battery I really loved having included.
It has a good marketable brand and 'appearance' for sure. A good Aura and level 3 magicks, but once you start leveling up your spell tree, like other comments in the thread have alluded to, the cracks start to show and you bleed out mana trying to scale what you initially thought would be an effortless process.
The really interesting part is message passing and easy peasy baked in communication that allows to to send messages to other erlang nodes. So building applications that talk to each other over networks is just a normal function of the language and not a higher level dependency such as a library.
The concurrency is also pretty neat as erlang treats all threads of execution as an erlang process. So merging that with the distribution and simple message passing you can easily build stuff that scales without much external tooling.
It's almost an OS unto itself. There are two interesting IoT systems which use it to such length such as GRiSP which is erlang beam ported to bare metal using RTEMS and Nerves which runs beam directly on top of a Linux kernel making beam the serspace.
Here are some more outside of Erlang, that I know of and I'm sure there's more.
APL/J/K - mathematical algorithms
Prolog - logic, tons of business rules
Forth/Lisp - bottom up programming, when you have an idea of the primitives you need to tackle a problem, but not exactly sure how to put it together.
Assembly - When you must absolutely run impossibly fast especially on very small CPUs
AWK/Perl - slice and dice text files
For these languages, I don't substitute for any language. I'll never slice and dice with Java, Python, Go. I don't care. Awk or Perl. I'll never implement tons of rules in any other language, I don't care what logic library they implement without first doing so in Prolog.
For the solo programmer, the above languages hold very true. I have played around with Erlang since Prolog influenced it's syntax, but I'm yet to have to build a large scale fault tolerant system that needs it, but the knowledge is tucked away at the back of my memory should I ever.
I feel that Python, Javascript and Go can also be some sort of secret weapon if used in the right place.
https://www.statista.com/statistics/258749/most-popular-glob...
Telegram's 200mm is MAUs, and that number is over 1 year older than Discord's information.
[1] http://www.erlang-factory.com/static/upload/media/1394234889...
The intent would be pre-process data and stream inward, or simply be a command-and-control interface -> process and provide response.
You can control everything remotely with nerves-hub, push update, debug etc. Remember you only have to burn the image once, then its all update from here.
You can build a poncho application where everything is side-by-side, lets say you have your app-firmware (you build image from this), then you build separate app-ui, app-logic, app-whatever etc. and simply hard code the path as dependencies in app-firmware and each app has their own configuration.
Everything will be bundled into a single image and protects you from things leaking in from the sides rather than from above.
Typically not suited for embedded.
(Assuming you mean embedded as in severely limited in resouces, and not "modern embedded" where you have lots and lots of unused system resources. If you mean the latter then anything goes.)
One example where a Nerves setup would be great is say a redundant onsite mini-cluster for processing and redundancy. As an alternative to say a k8s setup to manage devices with Nerves you could readily flash your "app code" to multiple RPi’s, connect them on a lan, and not have to have a separate clustering layer.
PS: I enjoy writing streaming code in Elixir (vs more procedural or OO methods). This is a snippet I use to decode a SLIP encoded binary UART stream with an CRC check:
Stream.repeatedly(fn -> receive_data_packet(timeout) end)
|> Stream.transform(<<@frame_end, @frame_end>>, &frame_splitter(&1, &2, {separator, max_buffer}))
|> Stream.map(&decode_slip(&1))
|> Stream.map(&frame_header(&1))
|> Stream.reject(&( &1[:code] == -1))
|> Stream.each(fn x -> if !x[:crc_check] do Logger.error("parser crc error: #{inspect x}") end end)
|> Stream.reject(&( &1[:crc_check] == false))
...But on the other hand the language compared to other modern languages is tiny and figuring out why something does not compile is a non-issue beyond an absolute beginner.
I use Elixir in production and Erlang in side projects.
10:21:21.525 mid=1 [error] GenServer {Registry.WatcherManagerRegistry, 1} terminating
** (CaseClauseError) no case clause matching: {:ok, <snip>}
(core) lib/core/http.ex:64: Core.Http.request/7
(core) lib/core/monitors/built_in_monitor.ex:99: Core.Monitors.BuiltInMonitor.perform_request/1
(core) lib/core/monitors/built_in_monitor.ex:76: Core.Monitors.BuiltInMonitor.perform/1
(core) lib/core/watcher.ex:40: Core.Watcher.perform_check/1
(core) lib/core/watcher_server.ex:91: Core.WatcherServer.handle_info/2However, RMQ did hit numerous issues that they had to work around on the Erlang platform. They had to engineer what was effectively their own scheduler on top of parts of the native Erlang one in order to prevent some starvation cases [1], and I have also heard that issues with Mnesia are at the root of some of the pathological behaviors (data loss) of some versions of RabbitMQ when restarting from a crash (this is admittedly anecdotal, so take it with a grain of salt).
[1] http://alvaro-videla.com/2013/09/rabbitmq-internals-credit-f...
https://www.erlang-solutions.com/resources/download.html
Linux distros have always been terrible places to find reliable packages.
Just wondering if such a system used in Poland, actually called Elixir[1], has a line of Erlang/Elixir in its codebase.
[1] https://pl.wikipedia.org/wiki/Elixir_(system_rozliczeń_międz...
Online gaming?
Collaborative tools?
Online gaming can be a good option—if building games is your thing. Personally, I find game-based demos/exercises with certain tools to be a bit too far removed from my daily work to help certain concepts really take root.
1. Erlang/Elixir are less than 1% of programming languages market.
2. Erlang/Elixir popularity is trending down.
https://www.quora.com/When-did-Facebook-switch-away-from-usi...
One might note, snidely [1], that three-four years after freezing development of an Erlang-based messaging system, starving maintenance work on that system of engineering effort, devoting massive engineering resources to a from-scratch C++ rewrite, and in the meantime blaming the language for relatively minor system design issues that could have been improved with a fraction of the effort (including, but not limited to, Erlang's ability to wrap allegedly critical C++ components) … Facebook plowed $19B into the acquisition of an Erlang-based messaging system.
[1] as a main author of the Facebook Chat version written in Erlang
> Facebook plowed $19B into the acquisition of an Erlang-based messaging system.
They didn't care what it was written in. They would've spent it on Whatsapp even it was written in PHP (like Slack). They paid for users and market penetration.
Major functions of WhatsApp are implemented in Erlang and they're actively worked on.
Source: Self. Engineer at FB.
[1] https://changelog.com/podcast/208
> I wasn’t thinking we could actually get WhatsApp-like scale, because when I read about WhatsApp, they were using FreeBSD and they forked Erlang and made some optimizations, they fine-tuned FreeBSD… So I was thinking that it was gonna be very difficult to try to replicate that kind of scale.
> So we were doing extra work, and it was really fulfilling to actually see that with minor changes in our initial best-effort approach with just a few tweaks was able to go to something that was able to get millions of connections. That was incredibly fulfilling to come full circle, and also it’s a great brag slide now, of showing that two million connections chart.
WhatsApp engineers have been quite clear that using Erlang was a great choice.
Highly doubt it. Here is Maxim Fedorov talking about scaling their cluster to 10000 nodes in 2018 https://www.youtube.com/watch?v=FJQyv26tFZ8 it would be pretty ridiculous for them to completely rewrite that in C++ one year later.
Isn't C++ a far more battle-tested language than Erlang? Hasn't C++ a far bigger community than Erlang?
To all whose concern is Memory Management, learn about C++11 (and newer standards): smart pointers and heavy use of RAII pattern work shamefully good
It is generally not a good idea at all to use C++ in network-facing applications.
(And even at Google most systems running C++ code are their core indexing and analytical systems, which are not directly related to their Internet-facing perimeter; there are some exceptions, of course).
That said, looking back at previous jobs there are many places -- particularly in ad-tech stuff -- where I used Java server side that I now think C++ would have been more appropriate (or these days, Rust). I wasted a lot of hours tuning for garbage collection that I'd love to have back.
And yes, there is a crapload of stuff that is internet facing that is C++.
Well, at some point it is a matter of personal preferences and tradeoffs. One time, I used to work on a high-frequency trading system written in Java... yes, in the environment with zero tolerance to GC latency. The core system was written with “off-heap Java” style, with memory blocks preallocated... and for the periphery everybody could use regular GC-enabled Java.
Could have written everything in C++, but everybody hated C++ so much they preferred heavily modified Java compilers and environments.
Afterwards, some parts of the core were rewritten in Rust... and there were no significant performance or other gains, so it was left as is.