Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor Api::Initializer #14624

Merged
merged 6 commits into from
May 3, 2017
Merged

Conversation

imtayadeway
Copy link
Contributor

For legacy reasons there were some quite expensive operations that were wrapped in the Api::Initializer class so their execution could be delayed until the first request. This code generates some data and uses that data to populate things like Api::Environment.normalized_attributes. By moving that code into Api::Environment and allowing it to be lazily evaluated, we achieve the same effect. What remains is merely logging which I've moved into the top level lib/api.rb, eliminating the need for this class.

To show that we are still delaying population of the normalized_attributes data until required, here's what happens when I open the console:

irb(main):001:0> Api::Environment.instance_variable_get(:@normalized_attributes)
=> nil
irb(main):002:0> Api::Environment.normalized_attributes
PostgreSQLAdapter#log_after_checkout, connection_pool: size: 16, connections: 1, in use: 1, waiting_in_queue: 0
=> {:time=>{"expires_on"=>true, "last_logon"=>true, "created_on"=>true, "updated_on"=>true, "created_at"=>true, "updated_at"=>true, "evaluated_on"=>true, "last_valid_on"=>true, "last_invalid_on"=>true, "credentials_changed_on"=>true, "commit_time"=>true, "last_import_on"=>true, "fulfilled_on"=>true, "creation_time"=>true, "last_perf_capture_on"=>true, "file_mtime"=>true, "last_scan_on"=>true, "timestamp"=>true, "last_sync_on"=>true, "last_scan_attempt_on"=>true, "retires_on"=>true, "boot_time"=>true, "state_changed_on"=>true, "ems_created_on"=>true, "retirement_last_warn"=>true, "start_time"=>true, "finish_time"=>true, "last_refresh_date"=>true, "last_metrics_update_date"=>true, "last_metrics_success_date"=>true, "scheduled_on"=>true, "last_run_on"=>true, "last_accessed_on"=>true, "started_on"=>true, "stopped_on"=>true, "last_heartbeat"=>true, "placed_at"=>true, "create_time"=>true, "install_time"=>true, "logo_updated_at"=>true, "login_logo_updated_at"=>true, "lastlogon"=>true, "lastlogoff"=>true}, :url=>{"href"=>true}, :resource=>{"image_href"=>true}, :encrypted=>{"password"=>true, "root_password"=>true, "sysprep_password"=>true, "sysprep_domain_password"=>true, "bind_pwd"=>true, "amazon_secret"=>true}}

As you can see, Rails has successfully booted without calling this expensive operation

This also allowed for a few ✂️ ✂️ ✂️

@miq-bot add-label api, refactoring
@miq-bot assign @abellotti

/cc @Fryguy

@miq-bot
Copy link
Member

miq-bot commented Apr 3, 2017

Checked commits imtayadeway/manageiq@30bd885~...edbc7c9 with ruby 2.2.6, rubocop 0.47.1, and haml-lint 0.20.0
3 files checked, 0 offenses detected
Everything looks good. 👍

@abellotti
Copy link
Member

👍 @imtayadeway

@Fryguy what was the tool you used to keep track of allocations upon instantiating rails/workers ?

@abellotti
Copy link
Member

@imtayadeway see ManageIQ/manageiq-gems-pending#123 for info about webtreemap, would be nice to see the numbers for the Api Controller before and after. Thanks

@@ -1,7 +1,30 @@
module Api
class Environment
def self.normalized_attributes
@normalized_attributes ||= {:time => {}, :url => {}, :resource => {}, :encrypted => {}}
@normalized_attributes ||= {
:time => time_attributes.each_with_object({}) { |attr, hsh| hsh[attr] = true },
Copy link
Member

@Fryguy Fryguy May 3, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Out of curiosity, is the true value used at all? If not, perhaps it would be better to use a Set over a Hash in all of these cases.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Fryguy I thought the same thing, but since hash lookup was faster I assumed it was there for that reason. Could we sacrifice a small performance gain for a more appropriate data structure?

Copy link
Member

@Fryguy Fryguy May 3, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Fryguy I thought this too, but when I benchmarked it was consistently slower (compared with SortedSet too). Nonetheless, I'll put a PR together so perhaps we can discuss this better there

end

def self.time_attributes
@time_attributes ||= begin
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The begin/end is redundant here. Also I'm not a fan of the mega indent, personally...I prefer

   def self.time_attributes
     @time_attributes ||=
       ApiConfig.collection... do
         
       end
   end

@Fryguy
Copy link
Member

Fryguy commented May 3, 2017

@imtayadeway I'm going to merge this anyway. Let's take my other comments into a separate PR.

@Fryguy Fryguy merged commit 4ee3863 into ManageIQ:master May 3, 2017
@Fryguy Fryguy added this to the Sprint 60 Ending May 8, 2017 milestone May 3, 2017
@Fryguy Fryguy added the fine/yes label May 3, 2017
@simaishi
Copy link
Contributor

simaishi commented Jun 9, 2017

@imtayadeway I assume there is no BZ for this? Not sure if this is one of those changes that any API call will go through this and no specific test is needed (in which case, I don't think BZ is needed), or if there are something QE will need to test to cover the changes made in this PR?

@imtayadeway
Copy link
Contributor Author

@simaishi no BZ for this. This PR was really just about code - the discussion about performance only relates to ensuring that there were no regressions in the refactoring. The existing tests should ensure that everything "still works" ;)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants