From 02135513c3572bd070dddef12dca3170090a0c13 Mon Sep 17 00:00:00 2001 From: Philipp Thun Date: Thu, 26 Aug 2021 12:02:37 +0200 Subject: [PATCH] Optimize JSON encoding - Add 'oj' gem. - Introduce optional 'use_optimized_json_encoder' config property. - If 'use_optimized_json_encoder' is true, use Oj (optimized for Rails) and omit 'as_json' calls for all Presenters. --- Gemfile | 1 + Gemfile.lock | 2 ++ config/initializers/json.rb | 20 ++++++++++++++++--- .../config_schemas/base/api_schema.rb | 2 ++ lib/cloud_controller/http_response_error.rb | 3 +++ 5 files changed, 25 insertions(+), 3 deletions(-) diff --git a/Gemfile b/Gemfile index 6a3726fee60..05b18ebf684 100644 --- a/Gemfile +++ b/Gemfile @@ -25,6 +25,7 @@ gem 'net-ssh' gem 'netaddr', '>= 2.0.4' gem 'newrelic_rpm' gem 'nokogiri', '>=1.10.5' +gem 'oj' gem 'palm_civet' gem 'posix-spawn', '~> 0.3.15' gem 'protobuf', '3.6.12' diff --git a/Gemfile.lock b/Gemfile.lock index 722c7b2936e..5b92a62aa02 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -308,6 +308,7 @@ GEM racc (~> 1.4) nokogiri (1.12.3-x86_64-linux) racc (~> 1.4) + oj (3.13.2) os (1.0.1) palm_civet (1.1.0) parallel (1.20.1) @@ -553,6 +554,7 @@ DEPENDENCIES netaddr (>= 2.0.4) newrelic_rpm nokogiri (>= 1.10.5) + oj palm_civet parallel_tests pg diff --git a/config/initializers/json.rb b/config/initializers/json.rb index 03d4eee48e2..627915a3b4d 100644 --- a/config/initializers/json.rb +++ b/config/initializers/json.rb @@ -1,7 +1,15 @@ require 'active_support/json/encoding' module CCInitializers - def self.json(_cc_config) + def self.json(cc_config) + if cc_config[:use_optimized_json_encoder] + MultiJson.use(:oj) + Oj::Rails.optimize # Use optimized encoders instead of as_json() methods for available classes. + Oj.default_options = { + bigdecimal_load: :bigdecimal, + } + end + ActiveSupport.json_encoder = Class.new do attr_reader :options @@ -10,10 +18,16 @@ def initialize(options=nil) end def encode(value) + if MultiJson.default_adapter == :oj && value.is_a?(VCAP::CloudController::Presenters::V3::BasePresenter) + v = value.to_hash + else + v = value.as_json(options.dup) + end + if Rails.env.test? - MultiJson.dump(value.as_json(options.dup)) + MultiJson.dump(v) else - MultiJson.dump(value.as_json(options.dup), options.merge(pretty: true)) + MultiJson.dump(v, options.merge(pretty: true)) end end end diff --git a/lib/cloud_controller/config_schemas/base/api_schema.rb b/lib/cloud_controller/config_schemas/base/api_schema.rb index 5a65033b598..ef3ad9a0375 100644 --- a/lib/cloud_controller/config_schemas/base/api_schema.rb +++ b/lib/cloud_controller/config_schemas/base/api_schema.rb @@ -351,6 +351,8 @@ class ApiSchema < VCAP::Config write_key: String, dataset: String, }, + + optional(:use_optimized_json_encoder) => bool, } end # rubocop:enable Metrics/BlockLength diff --git a/lib/cloud_controller/http_response_error.rb b/lib/cloud_controller/http_response_error.rb index e9f9cc799aa..1ca1fe15495 100644 --- a/lib/cloud_controller/http_response_error.rb +++ b/lib/cloud_controller/http_response_error.rb @@ -10,6 +10,9 @@ def initialize(message, method, response) begin source = MultiJson.load(response.body) + rescue ArgumentError + # Either Oj should raise Oj::ParseError instead of ArgumentError, or MultiJson should also wrap + # ArgumentError into MultiJson::Adapters::Oj::ParseError rescue MultiJson::ParseError source = response.body end