一个简单的delay server

web game里经常出现这样的需求:
1.建造一个房子,等待n秒后建好
2.种植一个植物,等待n秒后完成
3.生产一个汽车,等待n秒后完成
4.升级一个基地,等待n秒后完成
..................
无论是汽车还是房子,建造或升级这个动作很简单,只需要更新一下数据库里的某个字段。
关键是如何处理等待n秒这个操作。

[size=x-large]cron + rake[/size]
最简单的做法就是后台定时rake,每隔一段时间扫描一下整个表,根据结束时间去改变状态字段。
但是这样作的缺陷很明显,即使扫描的时间间隔再短也达不到准确,还有就是rake每次执行都要加载一次rails环境,然后再释放,这样效率很低。

[size=x-large]Delay Job:[/size]
看了各种delay job插件,这些插件主要解决的问题是异步的问题,同样达不到精确的计划。

[size=x-large]异步线程or进程+sleep n[/size]
这种方案看起来不错,但是无论线程还是进程,一直sleep都会占很多资源.

[size=x-large]EventMachine[/size]
[quote]EventMachine是一个基于Reactor设计模式的、用于网络编程和并发编程的框架。Reactor模式描述了一种服务处理器,它接受事件并将其分发给已注册的事件处理。这种模式的好处就是清晰的分离了时间分发和处理事件的应用程序逻辑,而不需引入多线程来把代码复杂化。[/quote]
好了,神器在手,,看代码:
Delay Server:


#!/usr/bin/env ruby

require 'rubygems'
require 'optparse'
require 'eventmachine'

require 'evma_httpserver'
require 'rack'

options = {
:Port => 3000,
:Host => "0.0.0.0",
:environment => (ENV['RAILS_ENV'] || "development").dup
}

ARGV.clone.options do |opts|
opts.on("-p", "--port=port", Integer,
"Runs Delay Server on the specified port.", "Default: 3000") { |v| options[:Port] = v }
opts.on("-b", "--binding=ip", String,
"Binds Delay Server to the specified ip.", "Default: 0.0.0.0") { |v| options[:Host] = v }

opts.on("-e", "--environment=name", String,
"Specifies the environment to run this server under (test/development/production).",
"Default: development") { |v| options[:environment] = v }

opts.separator ""

opts.on("-h", "--help", "Show this help message.") { puts opts; exit }

opts.parse!
end

puts "=> Delay Server starting on http://#{options[:Host]}:#{options[:Port]}"


ENV["RAILS_ENV"] = options[:environment]


require(File.join(File.dirname(__FILE__), 'config', 'boot'))
require(File.join(File.dirname(__FILE__), 'config', 'environment'))


class DelayServer < EM::Connection
include EM::HttpServer

def post_init
super
end

def process_http_request

params = Rack::Utils.parse_query(@http_query_string)

response = EM::DelegatedHttpResponse.new(self)
response.status = 200
response.content_type 'text/html'

current_time = Time.now
response.content = "request time -> #{current_time.to_s(:db)} / delay time -> #{params['delay']}s\n"

EM::add_timer(params["delay"]) do
p params["operate"]
puts Time.now.to_s(:db)
end

response.send_response
end
end


trap(:INT) { exit }

puts "=> Ctrl-C to shutdown server"

EM.run{
EM.start_server options[:Host], options[:Port], DelayServer
}




Rails Server:

class XxxController < ApplicationController
def build
#.................
system('%Q{curl "http://0.0.0.0:3000?delay=10&operate=build" > ./log/delay_server.log 2>&1 &})
#.................
end
end



其实rails server与delay server之间通讯可以有多种选择,比如drb
本着简单高效的原则,选择了http协议..
虽然eventmachine是非阻塞io,但是单个进程的吞吐量有限,利用http协议很容易在前面加个nginx,变成一个小集群....
[img]http://dl.iteye.com/upload/attachment/304943/25c7a6ba-3094-34e7-89b3-6ec6c33afe4c.png[/img]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值