Live data from Hacker News

Use Rails

jmduke.com

81–88 of 88 posts

Re: Use Rails

#81
post #80
post #75

Earlier quoted context omitted.

You're saying that NodeJS monolith comes with no downsides compared to Rails at early stages. We disagree here. From my brief surveys, nodejs ecosystem comes with less security out of the box, less standardized project structures, fewer thoroughly-designed and supported packages (vs cutting edge experiments), more complex upgrade paths, more projects getting abandoned, all of which can slow you down every day. Fricti…

"being in the corner at scale doesn't force you to rewrite everything. Just the piece that put you there. You can leave Rails app to handle most things, and extract parts of specialized infra as needed." You can't easily, because this now puts a network boundary between your Rails app and the part you extracted. A network boundary that requires you to do IO, which will (by default) cause you Rails app to blockingly w…

A internal network boundary is probably worth it for heavy jobs, since you usually don't want it to interfere with serving web requests (no matter the tech).

You probably already know what I would say to each of those examples.

> Rails timing out after 30s while allocating 500MB of memory (mostly) in ActiveRecord to compute 5MB of JSON to return to an API caller.

I can make a JS or Go program perform the same way. In fact the exact same thing happened in my shop with Go/Gorm. The key question is: how do you compute the 5mb of JSON? The devil is in those details. We changed the way we computed ours, and the issue was gone.

> 90% of request latency of ~10s spent waiting for downstream services to respond to requests. Most of these could be fired off concurrently (ie `Promise.all` in node). 9s/10s this Rails worker is sitting around doing nothing and eating up ~300MB of memory.

This sounds broken. Why is the worker doing nothing for 9 out of 10s? But like I said earlier, there are a bunch of ways to use HTTP1.1 pipelining to run them concurrently. (https://github.com/excon/excon and https://github.com/HoneyryderChuck/httpx support it, but you can also do that with Net::HTTP I believe) And you can still start threads, which are still concurrent while blocking on IO.

> trying to extract out Authorization to a centralized service (so that other extracted services don't have to call into the monolith in order to make authorization decisions) is a major pain as the monolith now has to make calls out to the centralized auth system to in order to make authz decisions.

This seems unrelated to Rails. Not sure why monolith can't continue handling authorization.

Re: Use Rails

#82
post #81
post #80

Earlier quoted context omitted.

"being in the corner at scale doesn't force you to rewrite everything. Just the piece that put you there. You can leave Rails app to handle most things, and extract parts of specialized infra as needed." You can't easily, because this now puts a network boundary between your Rails app and the part you extracted. A network boundary that requires you to do IO, which will (by default) cause you Rails app to blockingly w…

A internal network boundary is probably worth it for heavy jobs, since you usually don't want it to interfere with serving web requests (no matter the tech). You probably already know what I would say to each of those examples. > Rails timing out after 30s while allocating 500MB of memory (mostly) in ActiveRecord to compute 5MB of JSON to return to an API caller. I can make a JS or Go program perform the same way. In…

"I can make a JS or Go program perform the same way. In fact the exact same thing happened in my shop with Go/Gorm. The key question is: how do you compute the 5mb of JSON? The devil is in those details. We changed the way we computed ours, and the issue was gone."

The problem is ActiveRecord in my case. The data layout is not great (lots of joins through relationships, I think 12 tables or so). ActiveRecord objects are HUGE compared to the few bytes of actual data they hold.

What do you use (except raw sql) in Ruby if you cannot use ActiveRecord? There is no other ORM that's optimized for fast reads and I don't feel like writing one.

I actually reimplemented the same API endpoint in Go using https://github.com/go-jet/jet and measured 10MB of allocations and essentially zero overhead over queries itself, a 50x speedup.

Don't get me wrong, this is not what the typical Rails shop will deal with, but it definitely shows where limitations of Rails lie and I'm dealing with stuff like that on a weekly basis in my job, and it's not even a large Rails app (3M LOC).

Re: Use Rails

#83
post #82
post #81

Earlier quoted context omitted.

A internal network boundary is probably worth it for heavy jobs, since you usually don't want it to interfere with serving web requests (no matter the tech). You probably already know what I would say to each of those examples. > Rails timing out after 30s while allocating 500MB of memory (mostly) in ActiveRecord to compute 5MB of JSON to return to an API caller. I can make a JS or Go program perform the same way. In…

"I can make a JS or Go program perform the same way. In fact the exact same thing happened in my shop with Go/Gorm. The key question is: how do you compute the 5mb of JSON? The devil is in those details. We changed the way we computed ours, and the issue was gone." The problem is ActiveRecord in my case. The data layout is not great (lots of joins through relationships, I think 12 tables or so). ActiveRecord objects…

I agree that if you make a very complex query in ActiveRecord, it could eat a lot of resources.

That said, I would highly recommend going with raw queries for this sort of complexity, no matter the language. There are usually 2 kinds of queries: normal ORM-powered CRUD operations (which can get moderately complex), and hairy specialized report-style calculations. The latter I always recommend to keep in raw, well-written, well-commented SQL form. You can still wrap it into some nice object.

You could write them in something efficient like Jet or Elixir's Ecto, but for such a complex case I'd argue that you shouldn't obfuscate SQL at all. For all other cases ActiveRecord works well.

If you are serving these results in real time, something like materialized views (in postgres) would move the burden of calculation to when data changes, rather than when data is viewed.

And to tie it back to the original convo: a very efficient concurrent language doesn't solve these root causes, rather gives you more time not to address them, and allows you to get away with more neglect. There's some value in that, but you have to weigh it against the downsides mentioned in previous comments. If the language+framework is super efficient and has no downsides to its ecosystem and ergonomics, then there's no debate, I'd just use that.

Re: Use Rails

#84
post #82
post #81

Earlier quoted context omitted.

A internal network boundary is probably worth it for heavy jobs, since you usually don't want it to interfere with serving web requests (no matter the tech). You probably already know what I would say to each of those examples. > Rails timing out after 30s while allocating 500MB of memory (mostly) in ActiveRecord to compute 5MB of JSON to return to an API caller. I can make a JS or Go program perform the same way. In…

"I can make a JS or Go program perform the same way. In fact the exact same thing happened in my shop with Go/Gorm. The key question is: how do you compute the 5mb of JSON? The devil is in those details. We changed the way we computed ours, and the issue was gone." The problem is ActiveRecord in my case. The data layout is not great (lots of joins through relationships, I think 12 tables or so). ActiveRecord objects…

[deleted]

Re: Use Rails

#85

These days I prefer using a NodeJS framework like AdonisJS over Ruby on Rails, but Rails had an important role in getting us here.

What are you using for your ORM? Last I checked Prisma is the new hotness, but it's testing story is frankly unacceptable (i.e. manual DB purges, https://www.prisma.io/docs/orm/prisma-client/testing/integra... ).

I use Lucid which is also maintained by the AdonisJS team (it's built upon Knex). I do development with SQLite then migrate to MSSQL for production (the latter not my choice, but organizational, but it rolls with it just fine). It has served my needs well.

Re: Use Rails

#86
post #41

Earlier quoted context omitted.

It might also mean that if you know JS then use AdonisJS. Which has become Rails of JS and is pretty old and mature too.

Wow I'm surprised I never heard of it - probably because it's boring and "old" for JS standards... And not backed by FAANG. Thank you for sharing! Though I couldn't find out any well known companies using it (re battle tested) but some might just not disclose which is fine.

Yeah, my organization does not disclose, but I can say I've used AdonisJS in production in the financial industry for about for about 6 years now.

Re: Use Rails

#87
post #79
post #78

Earlier quoted context omitted.

I also have the feeling that you are talking to a different person. I'm talking about latency, you are talking about bandwidth. I'm talking about concurrency, you are talking about parallelism. You can scale up any Rails app super easily by throwing money at the problem, it's trivial. When a single page load or API request to it takes 20 seconds, it doesn't help you if you have 1000 servers that can respond to hundre…

The amount of APIs in the world that require concurrency within a single request scope to meet latency needs approaches zero. In practice, you don’t make that db call until the auth request is done and the user is verified. In practice, you don’t make the outgoing api call until you already have the results of the db call, because you need your data to form the outgoing request. Etc. APIs where intra request concurre…

"The amount of APIs in the world that require concurrency within a single request scope to meet latency needs approaches zero."

I've never worked on any non-Rails API where this was true. The Ruby community keeps telling me this, but in languages where concurrency is well supported, it gets used everywhere to a great extent. I obviously don't have hard data to support this, but your claim seems pretty far fetched to be honest.

"In practice, you don’t make that db call until the auth request is done and the user is verified"

Of course you optimistically do any idempotent DB operations while waiting for auth to succeed if you care about latency.

"you don’t make the outgoing api call until you already have the results of the db call, because you need your data to form the outgoing request"

These dependencies of course exist, but so do parts of the graph where they do not. You might want to make 2 or 5 outgoing calls based on your DB query and have to wait for 2 out of these 5 to make another DB query. This is so common that there are libraries like https://github.com/uber-go/cff to explicitly model those dependency graphs, visualize them and resolve them at runtime.

My theory is that system designs like this are just impractical to implement inside Rails today, which leads heavily Rails biased engineers to not even consider them, which leads Rails experienced developers to never have seen them, which in turn fuels the sentiment that they are rare. I'm not saying that you fall into this category, but from my experience many engineers who have only ever done Rails in their career do.

Re: Use Rails

#88
post #81
post #80

Earlier quoted context omitted.

"being in the corner at scale doesn't force you to rewrite everything. Just the piece that put you there. You can leave Rails app to handle most things, and extract parts of specialized infra as needed." You can't easily, because this now puts a network boundary between your Rails app and the part you extracted. A network boundary that requires you to do IO, which will (by default) cause you Rails app to blockingly w…

A internal network boundary is probably worth it for heavy jobs, since you usually don't want it to interfere with serving web requests (no matter the tech). You probably already know what I would say to each of those examples. > Rails timing out after 30s while allocating 500MB of memory (mostly) in ActiveRecord to compute 5MB of JSON to return to an API caller. I can make a JS or Go program perform the same way. In…

> This seems unrelated to Rails. Not sure why monolith can't continue handling authorization.

Agreed. You can totally keep some data in the monolith and some data in new services, and stitch them together if/as needed: https://www.osohq.com/post/distributed-authorization

Post reply on HN