3021: Use Oj to encode API responses, and to decode them in tests.
authorTom Clegg <tom@curoverse.com>
Sat, 10 Jan 2015 07:55:55 +0000 (02:55 -0500)
committerTom Clegg <tom@curoverse.com>
Wed, 14 Jan 2015 05:57:29 +0000 (00:57 -0500)
* We use the Oj and multi_json gems, which makes Oj the default JSON
  parser. However, Rails' ActiveRecord::Base overrides this and uses
  the native JSON parser, which is slow. In our case we have two
  render() calls that represent nearly all cases where we ask
  ActiveRecord to serialize for us. In both cases we already have a
  hash (not a model object), and we always want JSON responses. So we
  can fix the performance problem simply by calling Oj.dump()
  ourselves, and passing the resulting JSON (instead of the hash) to
  render().

More gory details:

* "ActiveRecord::Base.extend kills JSON performance":
  https://github.com/rails/rails/issues/9212

* "when freedom patches fight, nobody wins":
  https://github.com/intridea/multi_json/pull/138#issuecomment-24468223

services/api/app/controllers/application_controller.rb
services/api/test/test_helper.rb

index 54d5adb439c37e9cf9371fccec4e77ecee56b002..a771042e52cb7f4a6af35c8256eb10418da855ca 100644 (file)
@@ -77,7 +77,9 @@ class ApplicationController < ActionController::Base
   end
 
   def show
-    render json: @object.as_api_response(nil, select: @select)
+    render(text: Oj.dump(@object.as_api_response(nil, select: @select),
+                         mode: :compat).html_safe,
+           content_type: 'application/json')
   end
 
   def create
@@ -441,7 +443,8 @@ class ApplicationController < ActionController::Base
         except(:limit).except(:offset).
         count(:id, distinct: true)
     end
-    render json: @object_list
+    render(text: Oj.dump(@object_list, mode: :compat).html_safe,
+           content_type: 'application/json')
   end
 
   def remote_ip
index 216dd2d02d9ebaf3ab7b9fcd4345ad05bd374c9f..5ea6e62bfa73381e0f7e95b79aba31be7143ee08 100644 (file)
@@ -25,7 +25,7 @@ require 'rails/test_help'
 
 module ArvadosTestSupport
   def json_response
-    ActiveSupport::JSON.decode @response.body
+    Oj.load response.body
   end
 
   def api_token(api_client_auth_name)