Ruby Sinatra web apps with background work threads
In Java-land, I have often used the pattern of writing a servlet with an init() method that starts up one or more background work threads. Then while my web application is handling HTTP requests the background threads can be doing work like fetching RSS feeds for display in the web app, perform periodic maintenance like flushing old data from a database, etc. This is a simple pattern that is robust and easy to implement with a few extra lines of Java code and an extra servlet definition in a web.xml file.
In Ruby-land this pattern is even simpler to implement:
require 'rubygems' require 'sinatra' $sum = 0 Thread.new do # trivial example work thread while true do sleep 0.12 $sum += 1 end end get '/' do "Testing background work thread: sum is #{$sum}" endWhile the main thread is waiting for HTTP requests the background thread can do any other work. This works fine with Ruby 1.8.7 or any 1.9.*, but I would run this in JRuby for a long-running production app since JRuby uses the Java Thread class.
Hi Mark
ReplyDeleteThat source code is not working my source code..
require 'sinatra'
require 'rest_client'
require 'data_mapper'
require 'nokogiri'
require 'json'
require 'open-uri'
require 'sinatra/flash'
require 'will_paginate'
require 'will_paginate/array'
require 'date'
require 'time'
require 'thread'
DataMapper::setup(:default, "sqlite3://#{File.dirname(__FILE__)}/a.db")
class Ladder_data
include DataMapper::Resource
property :id, Serial
property :time, String
property :times2, String
property :start_point, String
property :ladder_type, String
property :answer, String
validates_uniqueness_of :times2
end
DataMapper.finalize
Ladder_data.auto_upgrade!
Thread.new do # trivial example work thread
while true do
$t=Time.now
$t=$t.min
$t=$t%2
if $t==0
a = JSON.parse( open("http://named.com/page/ladder/ajax/result.php").read )
b=a['times']
z=a['times2']
ladder = Ladder_data.new
ladder.time = b
ladder.times2 = z
c=a['start_point']
if c == 'first'
ladder.start_point = '왼쪽'
else
ladder.start_point= '오른쪽'
end
d=a['ladder_type']
if d == 'type1'
ladder.ladder_type ='3'
else
ladder.ladder_type = '4'
end
e=a['answer']
if e == 'EVEN'
ladder.answer='짝'
else
ladder.answer= '홀'
end
ladder.save
end
end
end
this is my source code.
I am not sure why your code does not work. One thing to try: copy your code, and remove all database calls, making it simple - then see if threads work for you. Also, are you running on Linux or OS X?
ReplyDeleteIf you try to access the same data in another thread (e.g. in a sinatra route) you had better use a mutex!
ReplyDeleterequire 'rubygems'
require 'sinatra'
require 'thread'
$sum = 0
$semaphore = Mutex.new
Thread.new do # trivial example work thread
while true do
sleep 0.12
$semaphore.synchronize { $sum += 1 }
end
end
get '/' do
$semaphore.synchronize { $sum += 10 }
"Testing background work thread: sum is #{$sum}"
end
Why do you need a mutex if one thread is reading and another is writing?
ReplyDeleteB7, I think you are correct that in this simple example a mutex is not needed.
ReplyDeleteIn this simple example, sure. The next thing the questioner will try is to modify the $sum outside of the worker thread, and bad things will happen.
ReplyDelete