Eugene,

I think your raise some very interesting points (and a bit of a can of worms). 
I cannot speak for anyone else, but I can say I think about the heart of the 
questions you ask. I do think there is some perspective missing here, and that 
is the perspective of the front end application that is at play. Specifically, 
I don't think Rails can really answer your question well without thinking about 
what Javascript apps will look like in 2, 5, and 10 years from now.

In no particular order, here are some responses:

* The Async response pattern is absolutely a thing and I've used it a lot. IN 
particular, I use it anytime I know the response can't be guaranteed to be 
delivered in under 250 ms. Connecting to a 3rd party API always meets this 
requirement-- since I have no control over the third party API. Every try to 
write a "Place Order" page? You're gonna want to enqueue a job and process that 
in the background and update the UI independently (just as you explained).

* In the future, more apps will be built using WebSockets technology- something 
you didn't mention.  You can write poller-- as Eugene described -- to support 
legacy browsers, all new browsers should support WebSockets and we should be 
taking advantage of this great technology. I think WebSockets will basically 
eliminate the need for the Poller and you'll have an asynchronous app where the 
server can push down changes to the client when the long-running jobs finish. 
This kind of architecture work superfast and can achieve massive scale. So yes, 
it's a real problem and something I too think about a lot. 

* I think the need for fast endpoint response times comes from the way Heroku 
is architected. In a cluster environment (Rackspace, EngineYard), people do 
things like configure load balancers and they tolerate their 3, 5, or 7 second 
response times. In Heroku, this basically creates a bottlenecked app for 
everyone. So I think the subtle part of what you're saying should be repeated 
and highlighted: 
        * The new distributed architecture of Heroku pushed for consistently 
high-performance (under 500ms) endpoints. 
        * The Rails Way does not encourage performance out of the box (although 
it is achievable), 
        * The reliance on the request-operation-response pattern does no 
support itself to a truly Async (and dyno- distributed) scalability model
        * Rails doesn't offer much in the way of dealing with or supporting 
Async architecture, specifically in the Client-Server interaction side of 
things. (Although there are many emerging technologies to do this)


So to me this seems to be the heart of the conflict. 


* Might I be a little radical and propose that in the future Rails will be 
considered *"customer"* (I said customer, not consumer) of Backbone, Angular, 
and/or Ember. For example, when I worked (for the first time) with an Ember.JS 
app (specifically, ember-data) using a Rails JSON back-end that used 
ActiveModel Serializers earlier this year, I was simply blown away. I had an 
A-ha moment that I haven't had in Rails in many, many years. I think a lot of 
your Async questions can take on new dimensions when thought of from that 
perspective. 

Not only is this kind of architecture a great idea, but it is where the rest of 
the non-Rails world is moving to as well and where the Rails Old guard is 
stubbornly entranced in their ways. (We're talking about a framework that still 
officially endorses unobtrusive declarative-based javascript, RJS and Turbolink 
as the way to make Ajax-based websites.) 

 That last point is really significant for me. I think Rails is a great 
back-end technology, and I think were a lot of newcomers the platform mess up 
by trying to think of it too much as a front-end technology. Compared to what 
the kinds are doing over in Node, Ember, Angular, we're the old guard now. 


Newcomers come into Rails and expect Rails to have the answer to address 
today's modern UX needs. While Rails exceeds at being a back-end technology and 
an amazing tool for domain modeling, it just doesn't meet today's UX needs. 
That's why a lot in web community is moving away from Rails and embracing newer 
Javascript frameworks. Although Rails is still HUGE (by the numbers), I've 
spent all year talking to people in the New York City Startup scene about 
technology and Rails is not what they are talking about.

I definitely some of the ideas you have, although I disagree with others.

You can reach me here or at [email protected] if you want to discuss 
offline.

-Jason







On Oct 26, 2014, at 10:22 PM, Eugene Gilburg <[email protected]> wrote:

> The Problem
> 
> I wonder how many people (I'm one of them) started with basic Rails 
> applications serving HTML, JSON, or both, and eventually ran into a point 
> where certain parts of the application became too slow, or were re-factored 
> to consume some 3rd party services, and ended up not being able to 
> synchronously serve the response in a timely manner, requiring switching to 
> asynchronous responses.
> 
> The Pattern
> 
> At an abstract level, the behaviour is as follows:
> Get request (could be either HTML or JSON)
> Initiate some kind of async job ("job" here is interpreted widely, could be 
> delayed/enqueue job or some other paradigm, point is, it's asynchronous to 
> the request and has no guaranteed completion time)
> Respond to requestor with 202 Accepted status, or some other status 
> signifying "we accepted your request but do not have a response yet)
> Include in response the URL client should check to visit response. Note that 
> this isn't necessarily always mapping nicely to CRUD in sense of returning 
> standard RESTful id. For example, nature of the job could be something like a 
> very complex search/report query, of the form /items/123?conditions=..., but 
> we can't just tell client to visit /items/123 for their result, because 
> different clients doing this search may request same resource but with 
> different filter conditions.
> Client will poll the URL returned at last step, which will either return 
> "check back later" status if response is not done, or the actual response if 
> it's finished (or, alternatively, 3rd URL to visit the finished response once 
> it's complete, which client will then visit to get their actual data).
> If response jobs need to be stored on server side, need some mechanism to 
> eventually clear them out.
> The Rails Way
> 
> You may look at above and say "well, you have a custom requirement, so write 
> yourself a custom solution, Rails can't read your mind". And you might be 
> right. But, on the other hand:
> Over many projects I've been on, this has been a very common requirement. For 
> many applications which scale beyond a certain point both load-wise and 
> 3rd-party-integration-wise, response times are often not guaranteed because 
> of dependencies you have no direct control over, and we can't just hang the 
> request until the job is done.
> I don't _know_ from the beginning when, and for which resources, I'll need 
> async request/response handling. I want to be able to Just Code stuff using 
> the basic simple Rails as I need it, and switch to async processing later for 
> needed endpoints only, as my application evolves. I want to be able to do 
> this with minimal changes on both API and internal implementation. For 
> example, if my regular controller uses current_user (from session), 
> current_account (from request), and other such variables, I want to be able 
> to continue using them in async controllers and not have to re-write the 
> whole controller/view after switching to async.
> I was inspired to start this discussion by the latest Enqueue work added in 
> Rails 4.2. After many years and many competing async job processors 
> (delayed_job, sidekiq, resque, etc.) Rails decided it made sense for them to 
> provide a wrapper API so that code can be written in a consistent way and the 
> implementation be relatively easy to change with no external impact. Just as 
> importantly, it now becomes possible to write code that is synchronous yet 
> uses the Enqueue API (using the "inline" adapter), and later pick and choose 
> which parts should become async based on the application evolution.
> 
> The Enqueue API makes the backend job processing easier to make async, but 
> the controller-level request-response handling is still a sore point:
>  The URL pattern for async responses is different from standard REST, making 
> migrations from sync to async requests painful and existing APIs changed.
> Rendering a RESTful response (either HTML or JSON) synchronously is trivial 
> in normal Rails controllers; rendering it async is not. Even seemingly simple 
> things like rendering an existing model/view is not easy without the familiar 
> controller context. There are some gems that try to encapsulate it by 
> constructing a custom controller and stubbing or caching, some examples 
> Google found. Unfortunately, doing this is tedious work and makes it 
> difficult to use existing session or request-based helpers like current_user 
> or other methods from controller or application helpers. A lot of 
> session/request caching and method re-definitions are needed.
> http://www.jonb.org/2013/01/25/async-rails.html
> http://alphahydrae.com/2013/06/rails-3-rendering-views-outside-a-controller/
> http://stackoverflow.com/questions/6318959/rails-how-to-render-a-view-partial-in-a-model
> This just doesn't seem a "Rails Way" to solve my problem, it makes me feel 
> like I'm fighting against the MVC/REST instead of leveraging it. :-(
> The Vision
> 
> What do you think of being able to do something like:
> 
> class ItemsController < ApplicationController::Base
>   respond_to_async :show
> 
> 
>   def show
>     ...
>   end
> end
> 
> Or
> 
> class ItemsController < ApplicationController::Base
> 
>   def show
>     render 'show', async: true
>   end
> end
> 
> 
> This would provide the ground work (e.g. REST/URL structure) to handle 
> requests in a way which would be possible to make asynchronous if and when 
> needed. Similar to Enqueue, there could be an "inline" pattern that behaves 
> synchronously, but allows smooth transition to true async later, e.g. 
> "redirect" would provide a response URL for client to visit.
> 
> Similar to the "enqueue" philosophy, the main purpose of the async 
> request/response API would not to actually force a specific implementation, 
> but to provide a wrapper API that the actual implementation can fit in. Users 
> can either write their custom async implementation or use a 3rd party gem, 
> but any such implementation should conform to the expectations set by the API.
> 
> The above snippets are just hypothetical examples of what such an API _might_ 
> be like, I'm open to totally different ideas to solve this problem too.
> 
> The Discussion
> 
> Have you previously worked with implementing SOA or other requests which 
> cannot be responded to immediately with final result because the job is too 
> slow or distributed? I'd love to hear your opinion about this! Some factors 
> to consider would be:
> What was the response type of your application? HTML or JSON? Did it support 
> normal forms, front-end JS frameworks, mobile APIs, etc?
> How did you handle such a problem? Was it similar to above or did you have a 
> drastically different way?
> Did you design your application to have asynchronous responses from day 1, or 
> did you start with a basic Rails application and had to make all or parts of 
> it respond asynchronously later? What was the migration like?
> Did you ever think that Rails could provide a more consistent standard and 
> easier migration path from sync to async responses?
> Or perhaps you didn't have to build such systems? Perhaps you think they 
> don't even make sense and are not The Rails Way and don't belong in Rails? 
> I'd love to hear from you too - if you think Rails helping to solve this 
> isn't the right approach, then what might the right solution be/look like?
> 
> All feedback welcome!
> 
> -- 
> You received this message because you are subscribed to the Google Groups 
> "Ruby on Rails: Talk" group.
> To unsubscribe from this group and stop receiving emails from it, send an 
> email to [email protected].
> To post to this group, send email to [email protected].
> To view this discussion on the web visit 
> https://groups.google.com/d/msgid/rubyonrails-talk/4c0f375b-5e8e-4e60-a51e-7978dee9d69d%40googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

----

Jason Fleetwood-Boldt
[email protected]
http://www.jasonfleetwoodboldt.com/writing

All material (c) Jason Fleetwood-Boldt 2014. Public conversations may be turned 
into blog posts (original poster information will be made anonymous). Email 
[email protected] with questions/concerns about this.

-- 
You received this message because you are subscribed to the Google Groups "Ruby 
on Rails: Talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/rubyonrails-talk/4DB87EBF-F95B-445D-B863-C49D4F1F821B%40datatravels.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to