Why do I have Rails views overhead when handling API requests? - ruby-on-rails

I noticed in my logs that when I'm hitting API endpoints, the rails built in profiling is reporting that it is spending some time in "views" (heroku extra logging info removed):
[2021-08-06T21:04:20.864743 #32] INFO -- : Started POST "/api/v1/places_in_bounds" for 24.184.254.41 at 2021-08-06 21:04:20 +0000
[2021-08-06T21:04:20.865565 #32] INFO -- : Processing by Api::V1::PlacesController#in_bounds as */*
[2021-08-06T21:04:20.865629 #32] INFO -- : Parameters: {"place"=>{"east"=>-38.800911000000006, "north"=>62.13593387702106, "south"=>-109.113411, "west"=>9.516666266458477}}
[2021-08-06T21:04:20.903245 #32] INFO -- : Completed 200 OK in 37ms (Views: 26.8ms | ActiveRecord: 2.3ms | Allocations: 28475)
...but I'm not rendering any views! It's an API endpoint, not an erb. What's going on? Are my jsonapi-serializer serializers counted as views? Short of cracking open rails itself or profiling the ruby interpreter, it's not obvious to me what's going on. It's not a huge overhead (usually much less than 50%), but presumably the answer will be useful to others!

Short answer is yes your JSON serialisers are counted, because you call render in your controller.
Both ActionController::Base and ActionController::API include ActionController::Instrumentation, which wraps render in a benchmark:
def render(*)
render_output = nil
self.view_runtime = cleanup_view_runtime do
Benchmark.ms { render_output = super }
end
render_output
end
So, regardless of what format you are rendering, it captures and logs the runtime:
def log_process_action(payload) #:nodoc:
messages, view_runtime = [], payload[:view_runtime]
messages << ("Views: %.1fms" % view_runtime.to_f) if view_runtime
messages
end

Related

Tournament-Systems creating driver

Now that the error has been fixed by adding require 'tournament_system' here is my new error:
This is the terminal:
Rendering html template
Rendered html template (0.0ms)
Rendered tourneys/index.html.erb within layouts/application (10.8ms)
Completed 401 Unauthorized in 16ms (Views: 0.3ms | ActiveRecord: 1.1ms)
RuntimeError - Not Implemented:
app/controllers/tourneys_controller.rb:77:in `tourn'
app/views/tourneys/index.html.erb:37:in `_app_views_tourneys_index_html_erb__1482772099755741577_70314301318160'
Started POST "/__better_errors/deabb75178ea93ac/variables" for ::1 at 2018-04-17 00:55:03 -0700
This is on the webpage
Not Implemented
tournapp/controllers/tourneys_controller.rb
72
73
74
75
76
77
78
79
80
81
82
def tourn
driver = Driver.new
# Generate a round of a single elimination tournament
TournamentSystem::SingleElimination.generate driver
#Challonge::Tournament.find(:all)
##teamArray2 = render html: "<div>#{Challonge::Tournament.find(:all)}</div>".html_safe
end
>>
This is a live shell. Type in here.
Request info
Request parameters
{"controller"=>"tourneys", "action"=>"index"}
Rack session
(object too large. Modify ActionDispatch::Request::Session#inspect or increase BetterErrors.maximum_variable_inspect_size)
Local Variables
driver
#<Driver:0x00007fe6a4eba5e0>
I believe the error has to do with not calling the driver correctly. Also I created the controller Tourney using a scaffold.
Your Class Driver was inhereting from TournamentSystem::Driver but that module was not available as it was not explicitly required.
Adding require 'tournament_system' should take care of that.
Regarding the NotImplemented error, this is not related to your code. If you follow the source code of def generate in module SingleElimination (source code) and traverse:
def generate calls create_matches which calls create_match which finally calls build_match and that has a raise 'Not Implemented'.
The Developer of the project has not completed implementing all the required functions.

Rails flash is missing eventually. Isn`t it thread-safe?

I have Rails application running on Thin with multithreading. There is a bunch of polling requests and sometimes, when running integration tests concurrent I have about 1-2% of missing flash failures. In my production.log I have something like the following in case of failure:
I, [2017-08-21T23:31:51.280455 #2146] INFO -- : Redirected to http://192.168.102.1/projects/599bcfd4875aa40862863a5b
I, [2017-08-21T23:31:51.282501 #2146] INFO -- : Rendered text template (0.1ms)
I, [2017-08-21T23:31:51.283151 #2146] INFO -- : Completed 200 OK in 3062ms (Views: 1.4ms)
I, [2017-08-21T23:31:51.309004 #23906] INFO -- : Rendered projects/_tests_block.html.haml (24.0ms)
I, [2017-08-21T23:31:51.309392 #23906] INFO -- : Rendered projects/show.js.haml within layouts/application (29.9ms)
I, [2017-08-21T23:31:51.318025 #23906] INFO -- : Completed 200 OK in 124ms (Views: 48.4ms)
I, [2017-08-21T23:31:51.318956 #2146] INFO -- : Started GET "/projects/599bcfd4875aa40862863a5b" for 192.168.102.2 at 2017-08-21 23:31:51 -0700
I, [2017-08-21T23:31:51.321849 #2146] INFO -- : Processing by ProjectsController#show as HTML
I, [2017-08-21T23:31:51.321994 #2146] INFO -- : Parameters: {"id"=>"599bcfd4875aa40862863a5b"}
My redirect call looks like redirect_to #project, notice: success_message
Between redirect and start of getting show page I have the finish of polling request from another page. In this case when show page is rendered, there is no flash[:notice].
I tried to keep and clear flash explicitly, so there is before_filter { flash.keep } in ApplicationController and flash.clear in my notification partial.
I also tried to log flashes before every action and in this concurrent case no another action steals flash, it's just missing.
Is this a multithreading problem? Or maybe I should use or implement flash with kind of "destination"? So that should be thread-safe too anyway.
PS Ruby 2.3.4, Rails 4.2.7, Thin 1.5.1

JSON Performance in Rails

I'm running a query on my index action in a Rails app, and if you look at the logs it's pretty fast:
Started GET "/apartments?within=-74.01798248291016%2C40.746346606483826%2C-73.8943862915039%2C40.79314877043915&per_page=500" for 127.0.0.1 at 2012-11-01 16:58:21 +0200
Processing by ApartmentsController#index as JSON
Parameters: {"within"=>"-74.01798248291016,40.746346606483826,-73.8943862915039,40.79314877043915", "per_page"=>"500"}
MONGODB (228ms) development['$cmd'].find({"count"=>"apartments", "query"=>{:status=>"available", :coordinates=>{"$within"=>{"$box"=>[[-74.01798248291016, 40.746346606483826], [-73.8943862915039, 40.79314877043915]]}}}, "fields"=>{:neighborhood_id=>0}}).limit(-1)
MONGODB (445ms) development['apartments'].find({:status=>"available", :coordinates=>{"$within"=>{"$box"=>[[-74.01798248291016, 40.746346606483826], [-73.8943862915039, 40.79314877043915]]}}}, {:neighborhood_id=>0}).limit(500).sort([[:qs, :desc]])
Completed 200 OK in 9737ms (Views: 8816.0ms)
If the DB query only takes 445ms, why does the JSON take almost 10 seconds to render and get sent back over the wire?
Is there a faster way to render the #apartments collection to JSON?
Use a different JSON serializer?
https://rubygems.org/gems/oj

Rails production.log (using Passenger) being written to by multiple processes, can't be parsed

Here's a snippet of my production.log:
Started GET "/product/514034/754240" for XX.XX.202.138 at 2012-06-21 11:52:28 -0700
Started GET "/product/614409/666897" for XX.XX.228.38 at 2012-06-21 11:52:28 -0700
Processing by ProductsController#show as HTML
Parameters: {"category_id"=>"514034", "product_id"=>"754240"}
Processing by ProductsController#show as HTML
Parameters: {"category_id"=>"614409", "product_id"=>"666897"}
Logged in 2940659 via auth cookie
Logged in 585210 via auth cookie
[e3e3fc56bb6bd137741b269ee397683c] [2940659] Read fragment views/global-caches/header (0.7ms)
[e3e3fc56bb6bd137741b269ee397683c] [2940659] Rendered shared/_email_form.html.haml (0.7ms)
[d81bb986be5acc0277c0c9e11b414249] [585210] Read fragment views/global-caches/sharebar-message (0.7ms)
[d81bb986be5acc0277c0c9e11b414249] [585210] Rendered shared/_email_form.html.haml (0.7ms)
...
As you can see, it's logging two concurrent sessions of two different users simultaneously to the same log file. This makes it impossible to parse my logs and determine, for example, the time it took to generate each kind of page, because the entries are not in the expected order of:
Started GET "/URL/BLAH" for IP at DATE
... stuff...
Completed 200 OK in XXms (ActiveRecord: YY.Yms)
Instead I get an unpredictable interleaved log like this:
Started GET "/URL/BLAH" for IP at DATE
Started GET "/URL/BLAH" for IP at DATE
... stuff...
Completed 200 OK in XXms (ActiveRecord: YY.Yms)
...stuff...
Completed 200 OK in XXms (ActiveRecord: YY.Yms)
So it's impossible to match the "completeds" with the "Started."
What I'd like is a way to have each child process write to its own log or something. Or if it's possible a way to write the each pageview's log atomically, but that might be impossible or difficult or hurt performance.
Rails 3.2 provides nice option config.log_tag
You can add to your production.rb:
config.log_tags = [ lambda { Time.now.to_i }]
So each line in your logs will be prepended by numbers. Example:
[1351867173] Started GET "/" for 127.0.0.1 at 2012-11-02 16:39:33 +0200
[1351867173] Processing by RecipesController#main as HTML
Logs are still shuffled, but now we can normalize, order them.
sort -f -s -k1.1,1.11 production.log | sed 's/^.............//' > sorted_production.log
(Sorter by first symbols (by timestamp) and remove timestamp by sed)
Now logs are easy to analyze.
In addition there is fix on related issue https://github.com/rails/rails/pull/7317 in rails 3.2.9
So keep this in mind.
Sorry for bad English... )

What is the difference in "Processing by Contoller#method as */*" and "Processing by BillsController#show as HTML"

All of my rails 3.2.2 ActiveRecord methods are being executed twice. I noticed that each execution is being processed differently, see the examples I grabbed from the console below...
Started GET "/api/bills/Jeremy%20Fox" for 127.0.0.1 at 2012-03-20 23:16:43 -0400
Processing by BillsController#show as HTML
Parameters: {"username"=>"Jeremy Fox"}
BillsForUsers Load (2.4ms) SELECT "bills_for_users".* FROM "bills_for_users" WHERE "bills_for_users"."billusername" = 'Jeremy Fox'
Completed 200 OK in 47ms (Views: 11.2ms | ActiveRecord: 2.4ms)
Started GET "/api/bills/Jeremy%20Fox" for 127.0.0.1 at 2012-03-20 23:16:44 -0400
Processing by BillsController#show as */*
Parameters: {"username"=>"Jeremy Fox"}
BillsForUsers Load (1.1ms) SELECT "bills_for_users".* FROM "bills_for_users" WHERE "bills_for_users"."billusername" = 'Jeremy Fox'
Completed 200 OK in 33ms (Views: 28.1ms | ActiveRecord: 1.1ms)
Can anyone explain to me why all of my ActiveRecord methods are being executed twice and/or what the difference is between Processing by BillsController#show as HTML and Processing by BillsController#show as */*?
Thanks.
It turns out the problem was actually the JSONView Chrome extension. As it states in the options menu...
Use safe method to parse HTTP response (*)
(*) : safe method forces the browser to send an extra HTTP request to get the raw HTTP content.
After spending days trying to figure out what I was doing wrong in my code, it was actually just chrome!
Hope no one else runs into this stupid issue.
-Jeremy
I've been grappling with this same issue. The HTML Validator Chrome extension is also guilty (with none of the fine print.)
In my case, I'm calling a ModestModel-backed search request, so the first hit (and rendering) was succeeding, followed by a phantom 500 as my non-DB search model was out of scope and nil on the second request.
Thanks, Jeremy!

Resources