However, let's take Ruby on Rails as an example. I have gotten MVP-quality software out in production. We can quickly validate whether this is something customers want. However, when the app starts getting traction, I have found that I need to reach for things outside a RoR monolith. Usually, the first thing is getting some kind of background processing job going, with Sidekiq and Resque.
At this point, we have shifted from a synchronous, no-shared-state architecture to one that requires background processing. This is where we start thinking in terms of concurrency and how to deal with it.
Since Rails is built on top of Ruby, Ruby does not have a sufficiently robust concurrency primitives that work well at scale. To use something like Sidekiq, we rely on using Redis. I have had projects where I need to pass data through a series of background jobs, like a pipeline. Now I am implementing what are effectively mutexes as a database column. I'm processing data that are effectively being streamed from third parties, so each individual Sidekiq job now has to have guards so that it can be idempotent. I have to be mindful of queues, analyzing where the bottlenecks, and how to structure the queues and tune how many of what kind of jobs should get resources. I have had to rely on outside monitoring solutions to make sure these processes stay up and running, and write things in a way so they can still recover on restart. I had to fork Sidekiq and rewrite core parts of it in order to create a different set of guarantees to fit a use-case -- a big deal to every Rubyist I had talked to, and yet, seems normal in the Erlang world.
In other words, in the Rails world, concurrency is handled in a very coarse-grained way, often relying on software outside of Ruby (such as Redis).
I found myself reinventing, in a very crude ways at a coarse-grained level, what OTP already offers. I adopted subversion and later git because I was crudely reinventing version control (shell script and tar); I dropped PHP and Perl CGI scripts in favor of Rails back when Rails was version 1.1 because I knew what a project that doesn't use what Rails offers would look like (a messy puddle). And likewise, now that I've found myself badly reinventing ideas OTP already has, it's the tool I'll reach for now.
With Erlang and Elixir, it is easier to reason with concurrency because the primitives are baked in deep, and it costs little to spin up something asynchronously. Reasoning with concurrency in the Rails world is treated more like black magic -- obscure, non-obvious, forbidden, potentially dangerous, and socially unacceptable.