$vehicle_providers = PeriodicUpdater.new(:period => 120){ VehicleWizardClient.get_providers }
$vehicle_providers.start
sleep(3) # make sure the first call completes before use
$vehicle_providers.get #=> [{:provider => ...}]
# change the provider list in VehicleWizard
sleep(120 + 3) # a little time for the call to complete, after the wait period
$vehicle_providers.get #=> [{:provider => ...}, {:provider => ...}]
Last active
August 29, 2015 13:56
-
-
Save tsnow/9275532 to your computer and use it in GitHub Desktop.
PeriodicUpdater Ruby
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Adapted from Crafting Rails Applications, by Jose Valim, SQL Metrics chapter, final example. http://pragprog.com/book/jvrails/crafting-rails-applications | |
# http://pragprog.com/titles/jvrails/source_code | |
# ./code/sql_metrics/5_final/lib/sql_metrics.rb | |
# And | |
# Go Programming Phrasebook http://www.informit.com/store/go-programming-language-phrasebook-9780321817143 | |
# http://www.informit.com/content/images/9780321817143/downloads/9780321817143_codeexamples.zip | |
# ./examples/concurrentMap.go | |
require 'thread' | |
class PeriodicUpdater | |
def initialize(args={:period => 60}, &action) | |
@period = args.fetch(:period) # in seconds | |
@action = action # what you want to happen | |
@data = nil # where that action's output will go | |
@queue = Queue.new # Pipe in requests to update the data and retrieve the data | |
@run_loop = nil # thread | |
@timer = nil # thread | |
@started = false # state var | |
end | |
def get | |
return @data unless @started | |
q = Queue.new | |
@queue.push(lambda{ q.push @data }) | |
q.pop | |
end | |
def run_loop | |
while !next_lambda.nil? | |
work | |
end | |
end | |
def next_lambda | |
@action_lambda = @queue.pop | |
end | |
def work | |
@action_lambda.call | |
end | |
def queue_update | |
@queue.push(lambda{ @data = @action.call }) | |
end | |
def periodic_updater | |
while true | |
sleep @period | |
queue_update | |
end | |
end | |
def stop | |
return self unless @started | |
@queue << nil # @run_loop will terminate after finishing pending requests | |
@run_loop.join | |
@run_loop = nil | |
@started = false | |
@timer.kill | |
@timer.join | |
@timer = nil | |
self | |
end | |
def start | |
@started = true | |
@run_loop = Thread.new{ run_loop } | |
queue_update | |
@timer = Thread.new{ periodic_updater } | |
self | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'test/unit' | |
require './periodic_updater' | |
class PeriodicUpdaterTests < Test::Unit::TestCase | |
def test_roundtrip | |
a = 0 | |
updater = PeriodicUpdater.new(:period => 2){ a += 1 } | |
assert_equal nil, updater.get | |
updater.start | |
assert_equal 1, updater.get | |
sleep 1 | |
assert_equal 1, updater.get | |
sleep 1 | |
assert_equal 2, updater.get | |
updater.stop | |
assert_equal 2, updater.get | |
sleep 3 | |
assert_equal 2, updater.get | |
end | |
end |
Ahh yes now I see why you queue it again in get
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@wbrady That's reasonable as well. And it might commute well with jcalvert's idea of storing the data in memcached. Something like: