{"action":"created","comment":{"url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/pulls/comments/24756040","id":24756040,"diff_hunk":"@@ -6,61 +6,79 @@\n #   # => {}\n #\n #   ExternalCountFecther.new.counts\n-#   # => {supporter_count: 12, volunteer_count: 12, called_voters_count: 12, called_reps_count: 12, house_supporters: 12, senate_supporters: 12, donations_total: 12, donations_count: 12}\n+#   # => {supporter_count: 12, volunteer_count: 12, called_voters_count: 12, reps_calls_count: 12, house_supporters: 12, senate_supporters: 12, donations_total: 12, donations_count: 12}\n  class ExternalCountFetcher\n-  attr_accessor :counter_hash\n+  include Redis::Objects\n \n-  COUNTER_HASH_KEYS = [:supporter_count, :volunteer_count, :called_voters_count, :called_reps_count, :house_supporters, :senate_supporters, :donations_total, :donations_count]\n+  REDIS_KEYS = [:supporter_count, :volunteer_count, :called_voters_count, :reps_calls_count, :house_supporters, :senate_supporters, :donations_total, :donations_count]\n+  REDIS_EXPIRE_SECONDS = 3.hours.to_i\n \n+  REDIS_KEYS.each do |key|\n+    counter key, :expiration => REDIS_EXPIRE_SECONDS\n+  end\n \n-  def initialize\n-    self.counter_hash = Redis::HashKey.new('external_counts', :expiration => 3.hours) #Note: expiration is only set when hash becomes non-empty\n+  def counts!\n+    fetch_empty_counts!\n+    counts\n   end\n \n   # Public: fetches all counts from external services. This is a high latency call and shouldn't only be called from a user request as a last resort\n-  # MARIO TODO: break out into multiple threads and redis keys, handle error cases\n-  def fetch_all!\n-    fetch_donations_total\n-    fetch_donations_count\n-    fetch_supporter_counts\n-    counter_hash.all\n+  #\n+  # reset - true|false  - if true, will fetch counters even if already set.\n+  def fetch_empty_counts!(reset: false)\n+    threads = []\n+    REDIS_KEYS.each do |key|\n+      threads << Thread.new do\n+        fetch_count(counter_key: key, reset: reset) if !redis_counter(key).exists? || reset\n+      end\n+    end\n+    threads.each &:join\n   end\n \n-  # Public: fetches all counts from external services. If the redis cache of counts is empty it will call `fetch_all!`\n+  # Public: fetches all counts from external services.\n   def counts\n-    counter_hash.empty? ? fetch_all! : counter_hash.all\n+    REDIS_KEYS.each_with_object({}) do |key, hash|\n+      hash[key] = redis_counter(key).value\n+    end\n   end\n \n   private\n \n-  def fetch_donations_total\n-    self.counter_hash[:donations_count] = Integration::PledgeService.donations_count\n-  end\n-\n-  def fetch_donations_count\n-    self.counter_hash[:donations_total] = Integration::PledgeService.donations_total\n-  end\n-\n-  def fetch_supporter_counts\n-    Integration::NationBuilder.list_counts.each do |key,count|\n-      self.counter_hash[key.to_sym] = count\n+  def fetch_count(counter_key:, reset: false)\n+    if counter_key =~ /supporter_count|volunteer_count/\n+      fetch_supporter_counts\n+    else\n+      count = case counter_key\n+        when :donations_count     then Integration::PledgeService.donations_count\n+        when :donations_total     then Integration::PledgeService.donations_total\n+        when :called_voters_count then 0\n+        when :reps_calls_count    then 0","path":"lib/external_count_fetcher.rb","position":74,"original_position":74,"commit_id":"fe92409e9bc6ff1b97df01e14b9b16215e2b24fa","original_commit_id":"fe92409e9bc6ff1b97df01e14b9b16215e2b24fa","user":{"login":"houndci","id":6697940,"avatar_url":"https://avatars.githubusercontent.com/u/6697940?v=3","gravatar_id":"","url":"https://api.github.com/users/houndci","html_url":"https://github.com/houndci","followers_url":"https://api.github.com/users/houndci/followers","following_url":"https://api.github.com/users/houndci/following{/other_user}","gists_url":"https://api.github.com/users/houndci/gists{/gist_id}","starred_url":"https://api.github.com/users/houndci/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/houndci/subscriptions","organizations_url":"https://api.github.com/users/houndci/orgs","repos_url":"https://api.github.com/users/houndci/repos","events_url":"https://api.github.com/users/houndci/events{/privacy}","received_events_url":"https://api.github.com/users/houndci/received_events","type":"User","site_admin":false},"body":"Indent `when` as deep as `case`.","created_at":"2015-02-16T15:12:50Z","updated_at":"2015-02-16T15:12:50Z","html_url":"https://github.com/MayOneUS/mayday-2.0-backend/pull/6#discussion_r24756040","pull_request_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/pulls/6","_links":{"self":{"href":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/pulls/comments/24756040"},"html":{"href":"https://github.com/MayOneUS/mayday-2.0-backend/pull/6#discussion_r24756040"},"pull_request":{"href":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/pulls/6"}}},"pull_request":{"url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/pulls/6","id":29326703,"html_url":"https://github.com/MayOneUS/mayday-2.0-backend/pull/6","diff_url":"https://github.com/MayOneUS/mayday-2.0-backend/pull/6.diff","patch_url":"https://github.com/MayOneUS/mayday-2.0-backend/pull/6.patch","issue_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/issues/6","number":6,"state":"open","locked":false,"title":"Count fetching Refactor","user":{"login":"Rio517","id":14241,"avatar_url":"https://avatars.githubusercontent.com/u/14241?v=3","gravatar_id":"","url":"https://api.github.com/users/Rio517","html_url":"https://github.com/Rio517","followers_url":"https://api.github.com/users/Rio517/followers","following_url":"https://api.github.com/users/Rio517/following{/other_user}","gists_url":"https://api.github.com/users/Rio517/gists{/gist_id}","starred_url":"https://api.github.com/users/Rio517/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Rio517/subscriptions","organizations_url":"https://api.github.com/users/Rio517/orgs","repos_url":"https://api.github.com/users/Rio517/repos","events_url":"https://api.github.com/users/Rio517/events{/privacy}","received_events_url":"https://api.github.com/users/Rio517/received_events","type":"User","site_admin":false},"body":"* refactor to make multi-threaded http requests\r\n* refactor to fetch any missing key\r\n* more testing for expiring redis keys\r\n\r\n@turino take a look when you have time!","created_at":"2015-02-14T22:42:35Z","updated_at":"2015-02-16T15:12:50Z","closed_at":null,"merged_at":null,"merge_commit_sha":"cd0d8eb9149477b8354ae9168d3f230416bc75d2","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/pulls/6/commits","review_comments_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/pulls/6/comments","review_comment_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/pulls/comments/{number}","comments_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/issues/6/comments","statuses_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/statuses/fe92409e9bc6ff1b97df01e14b9b16215e2b24fa","head":{"label":"MayOneUS:count_fetching","ref":"count_fetching","sha":"fe92409e9bc6ff1b97df01e14b9b16215e2b24fa","user":{"login":"MayOneUS","id":7469720,"avatar_url":"https://avatars.githubusercontent.com/u/7469720?v=3","gravatar_id":"","url":"https://api.github.com/users/MayOneUS","html_url":"https://github.com/MayOneUS","followers_url":"https://api.github.com/users/MayOneUS/followers","following_url":"https://api.github.com/users/MayOneUS/following{/other_user}","gists_url":"https://api.github.com/users/MayOneUS/gists{/gist_id}","starred_url":"https://api.github.com/users/MayOneUS/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/MayOneUS/subscriptions","organizations_url":"https://api.github.com/users/MayOneUS/orgs","repos_url":"https://api.github.com/users/MayOneUS/repos","events_url":"https://api.github.com/users/MayOneUS/events{/privacy}","received_events_url":"https://api.github.com/users/MayOneUS/received_events","type":"Organization","site_admin":false},"repo":{"id":29715441,"name":"mayday-2.0-backend","full_name":"MayOneUS/mayday-2.0-backend","owner":{"login":"MayOneUS","id":7469720,"avatar_url":"https://avatars.githubusercontent.com/u/7469720?v=3","gravatar_id":"","url":"https://api.github.com/users/MayOneUS","html_url":"https://github.com/MayOneUS","followers_url":"https://api.github.com/users/MayOneUS/followers","following_url":"https://api.github.com/users/MayOneUS/following{/other_user}","gists_url":"https://api.github.com/users/MayOneUS/gists{/gist_id}","starred_url":"https://api.github.com/users/MayOneUS/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/MayOneUS/subscriptions","organizations_url":"https://api.github.com/users/MayOneUS/orgs","repos_url":"https://api.github.com/users/MayOneUS/repos","events_url":"https://api.github.com/users/MayOneUS/events{/privacy}","received_events_url":"https://api.github.com/users/MayOneUS/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/MayOneUS/mayday-2.0-backend","description":"The API-driven next generation MADAY.us site","fork":false,"url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend","forks_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/forks","keys_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/keys{/key_id}","collaborators_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/teams","hooks_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/hooks","issue_events_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/issues/events{/number}","events_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/events","assignees_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/assignees{/user}","branches_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/branches{/branch}","tags_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/tags","blobs_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/git/refs{/sha}","trees_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/git/trees{/sha}","statuses_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/statuses/{sha}","languages_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/languages","stargazers_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/stargazers","contributors_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/contributors","subscribers_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/subscribers","subscription_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/subscription","commits_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/commits{/sha}","git_commits_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/git/commits{/sha}","comments_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/comments{/number}","issue_comment_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/issues/comments/{number}","contents_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/contents/{+path}","compare_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/compare/{base}...{head}","merges_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/merges","archive_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/downloads","issues_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/issues{/number}","pulls_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/pulls{/number}","milestones_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/milestones{/number}","notifications_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/labels{/name}","releases_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/releases{/id}","created_at":"2015-01-23T03:50:45Z","updated_at":"2015-02-16T14:53:35Z","pushed_at":"2015-02-16T15:12:42Z","git_url":"git://github.com/MayOneUS/mayday-2.0-backend.git","ssh_url":"git@github.com:MayOneUS/mayday-2.0-backend.git","clone_url":"https://github.com/MayOneUS/mayday-2.0-backend.git","svn_url":"https://github.com/MayOneUS/mayday-2.0-backend","homepage":null,"size":570,"stargazers_count":0,"watchers_count":0,"language":"Ruby","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":2,"forks":0,"open_issues":2,"watchers":0,"default_branch":"master"}},"base":{"label":"MayOneUS:master","ref":"master","sha":"1f54875630a4d1a4e095471f8739fbf1afd2fb83","user":{"login":"MayOneUS","id":7469720,"avatar_url":"https://avatars.githubusercontent.com/u/7469720?v=3","gravatar_id":"","url":"https://api.github.com/users/MayOneUS","html_url":"https://github.com/MayOneUS","followers_url":"https://api.github.com/users/MayOneUS/followers","following_url":"https://api.github.com/users/MayOneUS/following{/other_user}","gists_url":"https://api.github.com/users/MayOneUS/gists{/gist_id}","starred_url":"https://api.github.com/users/MayOneUS/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/MayOneUS/subscriptions","organizations_url":"https://api.github.com/users/MayOneUS/orgs","repos_url":"https://api.github.com/users/MayOneUS/repos","events_url":"https://api.github.com/users/MayOneUS/events{/privacy}","received_events_url":"https://api.github.com/users/MayOneUS/received_events","type":"Organization","site_admin":false},"repo":{"id":29715441,"name":"mayday-2.0-backend","full_name":"MayOneUS/mayday-2.0-backend","owner":{"login":"MayOneUS","id":7469720,"avatar_url":"https://avatars.githubusercontent.com/u/7469720?v=3","gravatar_id":"","url":"https://api.github.com/users/MayOneUS","html_url":"https://github.com/MayOneUS","followers_url":"https://api.github.com/users/MayOneUS/followers","following_url":"https://api.github.com/users/MayOneUS/following{/other_user}","gists_url":"https://api.github.com/users/MayOneUS/gists{/gist_id}","starred_url":"https://api.github.com/users/MayOneUS/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/MayOneUS/subscriptions","organizations_url":"https://api.github.com/users/MayOneUS/orgs","repos_url":"https://api.github.com/users/MayOneUS/repos","events_url":"https://api.github.com/users/MayOneUS/events{/privacy}","received_events_url":"https://api.github.com/users/MayOneUS/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/MayOneUS/mayday-2.0-backend","description":"The API-driven next generation MADAY.us site","fork":false,"url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend","forks_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/forks","keys_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/keys{/key_id}","collaborators_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/teams","hooks_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/hooks","issue_events_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/issues/events{/number}","events_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/events","assignees_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/assignees{/user}","branches_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/branches{/branch}","tags_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/tags","blobs_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/git/refs{/sha}","trees_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/git/trees{/sha}","statuses_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/statuses/{sha}","languages_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/languages","stargazers_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/stargazers","contributors_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/contributors","subscribers_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/subscribers","subscription_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/subscription","commits_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/commits{/sha}","git_commits_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/git/commits{/sha}","comments_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/comments{/number}","issue_comment_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/issues/comments/{number}","contents_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/contents/{+path}","compare_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/compare/{base}...{head}","merges_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/merges","archive_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/downloads","issues_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/issues{/number}","pulls_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/pulls{/number}","milestones_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/milestones{/number}","notifications_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/labels{/name}","releases_url":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/releases{/id}","created_at":"2015-01-23T03:50:45Z","updated_at":"2015-02-16T14:53:35Z","pushed_at":"2015-02-16T15:12:42Z","git_url":"git://github.com/MayOneUS/mayday-2.0-backend.git","ssh_url":"git@github.com:MayOneUS/mayday-2.0-backend.git","clone_url":"https://github.com/MayOneUS/mayday-2.0-backend.git","svn_url":"https://github.com/MayOneUS/mayday-2.0-backend","homepage":null,"size":570,"stargazers_count":0,"watchers_count":0,"language":"Ruby","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":2,"forks":0,"open_issues":2,"watchers":0,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/pulls/6"},"html":{"href":"https://github.com/MayOneUS/mayday-2.0-backend/pull/6"},"issue":{"href":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/issues/6"},"comments":{"href":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/issues/6/comments"},"review_comments":{"href":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/pulls/6/comments"},"review_comment":{"href":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/pulls/comments/{number}"},"commits":{"href":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/pulls/6/commits"},"statuses":{"href":"https://api.github.com/repos/MayOneUS/mayday-2.0-backend/statuses/fe92409e9bc6ff1b97df01e14b9b16215e2b24fa"}}}}