$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 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 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 |
@wbrady That's reasonable as well. And it might commute well with jcalvert's idea of storing the data in memcached. Something like:
class VehicleWizardFleets
def self.all
Rails.cache.read(:vehicle_wizard_fleets)
end
def self.store(data)
Rails.cache.write(:vehicle_wizard_fleets, data)
end
end
class VehicleWizardFleetsController < ApplicationController
def create
VehicleWizardFleets.store(params)
render :text => 'stored'
rescue => e
render :text => e.message, :status => 500
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
Why does the get method push another lambda onto the queue rather than just accessing
@data
?This is a really interesting idea but rather than poll for changes, I feel like it would be better to have Vehicle Wizard (in this case) push changes to RC when it knows its own data changed.