FIX: Fetch stats if it has not been cached.

This commit is contained in:
Guo Xiang Tan 2016-04-21 14:45:16 +08:00
parent e7d1fa8120
commit b4e0c5afe0
No known key found for this signature in database
GPG key ID: 19C321C8952B0F72
7 changed files with 53 additions and 38 deletions

View file

@ -1,13 +1,9 @@
module Jobs module Jobs
class AboutStats < Jobs::Scheduled class AboutStats < Jobs::Scheduled
include Jobs::Stats
every 30.minutes every 30.minutes
def execute(args) def execute(args)
stats = About.new.stats About.refresh_stats
set_cache(About, stats)
stats
end end
end end
end end

View file

@ -1,7 +1,5 @@
module Jobs module Jobs
class DashboardStats < Jobs::Scheduled class DashboardStats < Jobs::Scheduled
include Jobs::Stats
every 30.minutes every 30.minutes
def execute(args) def execute(args)
@ -12,9 +10,7 @@ module Jobs
GroupMessage.create(Group[:admins].name, :dashboard_problems, {limit_once_per: 7.days.to_i}) GroupMessage.create(Group[:admins].name, :dashboard_problems, {limit_once_per: 7.days.to_i})
end end
stats = AdminDashboardData.fetch_stats AdminDashboardData.refresh_stats
set_cache(AdminDashboardData, stats)
stats
end end
end end
end end

View file

@ -1,9 +0,0 @@
module Jobs
module Stats
def set_cache(klass, stats)
# Add some extra time to the expiry so that the next job run has plenty of time to
# finish before previous cached value expires.
$redis.setex klass.stats_cache_key, (klass.recalculate_stats_interval + 5).minutes, stats.to_json
end
end
end

View file

@ -18,7 +18,22 @@ module StatsCacheable
def fetch_cached_stats def fetch_cached_stats
# The scheduled Stats job is responsible for generating and caching this. # The scheduled Stats job is responsible for generating and caching this.
stats = $redis.get(stats_cache_key) stats = $redis.get(stats_cache_key)
stats ? JSON.parse(stats) : nil stats = refresh_stats if !stats
JSON.parse(stats).with_indifferent_access
end
def refresh_stats
stats = fetch_stats.to_json
set_cache(stats)
stats
end
private
def set_cache(stats)
# Add some extra time to the expiry so that the next job run has plenty of time to
# finish before previous cached value expires.
$redis.setex stats_cache_key, (recalculate_stats_interval + 5).minutes, stats
end end
end end
end end

View file

@ -1,10 +1,16 @@
require 'rails_helper' require 'rails_helper'
describe Jobs::AboutStats do describe Jobs::AboutStats do
after do
$redis.flushall
end
it 'caches the stats' do it 'caches the stats' do
stats = { "visited" => 10 } stats = About.fetch_stats.to_json
About.any_instance.expects(:stats).returns(stats) cache_key = About.stats_cache_key
$redis.expects(:setex).with(About.stats_cache_key, 35.minutes, stats.to_json)
expect($redis.get(cache_key)).to eq(nil)
expect(described_class.new.execute({})).to eq(stats) expect(described_class.new.execute({})).to eq(stats)
expect($redis.get(cache_key)).to eq(stats)
end end
end end

View file

@ -1,10 +1,18 @@
require 'rails_helper' require 'rails_helper'
describe Jobs::DashboardStats do describe Jobs::DashboardStats do
after do
$redis.flushall
end
it 'caches the stats' do it 'caches the stats' do
json = { "visited" => 10 } Timecop.freeze do
AdminDashboardData.any_instance.expects(:as_json).returns(json) stats = AdminDashboardData.fetch_stats.to_json
$redis.expects(:setex).with(AdminDashboardData.stats_cache_key, 35.minutes, json.to_json) cache_key = AdminDashboardData.stats_cache_key
expect(described_class.new.execute({})).to eq(json)
expect($redis.get(cache_key)).to eq(nil)
expect(described_class.new.execute({})).to eq(stats)
expect($redis.get(cache_key)).to eq(stats)
end
end end
end end

View file

@ -1,22 +1,25 @@
shared_examples_for 'stats cachable' do shared_examples_for 'stats cachable' do
describe 'fetch_cached_stats' do describe 'fetch_cached_stats' do
it 'returns the cached stats' do after do
begin $redis.flushall
stats = { "visits" => 10 }
$redis.set(described_class.stats_cache_key, stats.to_json)
expect(described_class.fetch_cached_stats).to eq(stats)
ensure
$redis.del(described_class.stats_cache_key)
end
end end
it 'returns nil if no stats has been cached' do it 'returns the cached stats' do
expect(described_class.fetch_cached_stats).to eq(nil) stats = described_class.fetch_stats.to_json
$redis.set(described_class.stats_cache_key, stats)
expect(described_class.fetch_cached_stats).to eq(JSON.parse(stats))
end
it 'returns fetches the stats if stats has not been cached' do
Timecop.freeze do
$redis.del(described_class.stats_cache_key)
expect(described_class.fetch_cached_stats).to eq(JSON.parse(described_class.fetch_stats.to_json))
end
end end
end end
describe 'fetch_stats' do describe 'fetch_stats' do
it 'has been implemented' do it 'has not been implemented' do
expect{ described_class.fetch_stats }.to_not raise_error expect{ described_class.fetch_stats }.to_not raise_error
end end
end end