gongren 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -4,6 +4,8 @@ Gongren distributes jobs to workers, with support for failed worker daemons and
4
4
 
5
5
  Gongren is Chinese worker: 工人. See http://www.ehow.com/video_4403851_say-worker-chinese.html for pronunciation.
6
6
 
7
+ Gongren uses prior work by Dan DeLeo: http://github.com/danielsdeleo/qusion/
8
+
7
9
  == Note on Patches/Pull Requests
8
10
 
9
11
  * Fork the project.
data/Rakefile CHANGED
@@ -80,3 +80,23 @@ rescue LoadError
80
80
  abort "YARD is not available. In order to run yardoc, you must: sudo gem install yard"
81
81
  end
82
82
  end
83
+
84
+ namespace :version do
85
+ task :rewrite do
86
+ require "erb"
87
+ require "ostruct"
88
+
89
+ version = Rake.application.jeweler.version_helper.to_s
90
+ template = ERB.new <<-EOT.gsub(/^\s{6}/, "")
91
+ # Nothing interesting here: see {Gongren::Server} or {Gongren::Worker}.
92
+ module Gongren
93
+ VERSION = "<%= version %>"
94
+ end
95
+ EOT
96
+ File.open(File.join(Dir.pwd, "lib/gongren.rb"), "w") {|out| out.puts template.result(binding)}
97
+ end
98
+ end
99
+
100
+ task "version:bump:patch" => "version:rewrite"
101
+ task "version:bump:minor" => "version:rewrite"
102
+ task "version:bump:major" => "version:rewrite"
@@ -0,0 +1,14 @@
1
+ require "rubygems"
2
+ begin
3
+ require "gongren/worker"
4
+ rescue LoadError
5
+ path = File.expand_path(File.join(File.dirname(__FILE__), "../../lib"))
6
+ raise if $LOAD_PATH.include?(path)
7
+
8
+ $LOAD_PATH.unshift(path)
9
+ retry
10
+ end
11
+
12
+ Gongren::Worker.start do |message|
13
+ p message[:time]
14
+ end
@@ -0,0 +1,17 @@
1
+ require "rubygems"
2
+ begin
3
+ require "gongren/server"
4
+ rescue LoadError
5
+ path = File.expand_path(File.join(File.dirname(__FILE__), "../../lib"))
6
+ raise if $LOAD_PATH.include?(path)
7
+
8
+ $LOAD_PATH.unshift(path)
9
+ retry
10
+ end
11
+
12
+ Gongren::Server.start do |server|
13
+ # On every tick, submit an event
14
+ EM.add_periodic_timer(1) do
15
+ server.submit("tick", :time => Time.now.utc)
16
+ end
17
+ end
@@ -0,0 +1,15 @@
1
+ require "rubygems"
2
+ begin
3
+ require "gongren/worker"
4
+ rescue LoadError
5
+ path = File.expand_path(File.join(File.dirname(__FILE__), "../../lib"))
6
+ raise if $LOAD_PATH.include?(path)
7
+
8
+ $LOAD_PATH.unshift(path)
9
+ retry
10
+ end
11
+
12
+ Gongren::Worker.start do |message|
13
+ p message[:time]
14
+ sleep 1.8 # Ensure we can never catch up
15
+ end
@@ -0,0 +1,17 @@
1
+ require "rubygems"
2
+ begin
3
+ require "gongren/server"
4
+ rescue LoadError
5
+ path = File.expand_path(File.join(File.dirname(__FILE__), "../../lib"))
6
+ raise if $LOAD_PATH.include?(path)
7
+
8
+ $LOAD_PATH.unshift(path)
9
+ retry
10
+ end
11
+
12
+ Gongren::Server.start do |server|
13
+ # On every tick, submit an event
14
+ EM.add_periodic_timer(1) do
15
+ server.submit("tick", :time => Time.now.utc)
16
+ end
17
+ end
@@ -1,4 +1,4 @@
1
1
  # Nothing interesting here: see {Gongren::Server} or {Gongren::Worker}.
2
2
  module Gongren
3
- VERSION = "0.0.1"
3
+ VERSION = "0.1.1"
4
4
  end
@@ -1,58 +1,59 @@
1
+ require "mq"
1
2
  require "logger"
2
- require "qusion"
3
3
 
4
4
  module Gongren
5
- # This version is intimately tied to Rails.
6
5
  class Server
7
6
  def initialize(options={})
8
7
  @options = options.inject(Hash.new) {|memo, (k,v)| memo[k.to_sym] = v; memo} # #symbolize_keys
9
8
  @logger = options[:logger] || Logger.new(options[:log] || STDERR)
10
9
  end
11
10
 
12
- # Submits a unit of work to the pool of workers.
13
- def self.submit(name, unit)
14
- data = Marshal.dump(unit)
15
- topic.publish(data, :persistent => true, :key => "unit.#{name}")
16
- end
17
-
18
11
  # A quick way to instantiate a server with some options.
19
- def self.start(options={})
20
- new(options).start
12
+ def self.start(options={}, &block)
13
+ new(options).start(&block)
21
14
  end
22
15
 
23
- # Starts the reactor / event loop.
16
+ # Starts the reactor / event loop. This method never returns.
17
+ # Must pass a block to yield to, enabling you to do useful work.
18
+ # The block must return a 2 element Array:
19
+ # <tt>["name of work unit", object]</tt>
20
+ #
21
+ # You must provide a block to which an instance of Gongren::Server will be yielded.
24
22
  def start
25
- logger.info { "Gongren::Server #{Process.pid} starting" }
26
- Qusion.start(@options)
27
- self.class.control_topic # Instantiates the control topic, for later use
23
+ logger.info { "Gongren::Server #{Process.pid} starting with options: #{options.inspect}" }
24
+
25
+ AMQP.start(options) do
26
+ @units = MQ.topic(exchange_name, exchange_options)
27
+ @control = MQ.topic(control_exchange_name, control_exchange_options)
28
+
29
+ yield self
30
+ end
31
+ end
32
+
33
+ def submit(name, message)
34
+ logger.debug { "Submitting #{name.inspect}: #{message.inspect}" }
35
+ data = Marshal.dump(message)
36
+ @units.publish(data, :persistent => true, :key => "unit.#{name}")
28
37
  end
29
38
 
30
39
  private
31
40
 
32
41
  attr_reader :options, :logger
33
42
 
34
- def self.exchange_name
43
+ def exchange_name
35
44
  "gongren.work"
36
45
  end
37
46
 
38
- def self.exchange_options
47
+ def exchange_options
39
48
  {:durable => true}
40
49
  end
41
50
 
42
- def self.topic
43
- Qusion.channel.topic(exchange_name, exchange_options)
44
- end
45
-
46
- def self.control_exchange_name
51
+ def control_exchange_name
47
52
  "gongren.worker.control"
48
53
  end
49
54
 
50
- def self.control_exchange_options
55
+ def control_exchange_options
51
56
  {}
52
57
  end
53
-
54
- def self.control_topic
55
- Qusion.channel.topic(control_exchange_name, control_exchange_options)
56
- end
57
58
  end
58
59
  end
@@ -39,12 +39,12 @@ module Gongren
39
39
  @logger = options[:logger] || Logger.new(options[:log] || STDERR)
40
40
  end
41
41
 
42
- def run
43
- raise ArgumentError, "#run must be called with a block" unless block_given?
42
+ def start
43
+ raise ArgumentError, "#start must be called with a block" unless block_given?
44
44
 
45
45
  logger.info { "Gongren::Worker #{worker_id} ready to work" }
46
46
 
47
- EM.run do
47
+ AMQP.start do
48
48
  MQ.queue(control_queue_name, control_queue_options).bind(control_exchange_name, control_exchange_options) do |header, data|
49
49
  message = Marshal.load(data)
50
50
  logger.info { message.inspect }
@@ -60,7 +60,7 @@ module Gongren
60
60
  end
61
61
  end
62
62
 
63
- MQ.queue(queue_name, queue_options).bind(exchange_name, exchange_options).subscribe do |header, data|
63
+ MQ.queue(queue_name, queue_options).bind(exchange_name, exchange_options).subscribe(:ack => true) do |header, data|
64
64
  message = Marshal.load(data)
65
65
  class << message; include Unit; end # Dynamically add our #ack method
66
66
  message.gongren_header = header
@@ -85,10 +85,12 @@ module Gongren
85
85
 
86
86
  # A quick way to run a worker. Creates an instance with the options and runs the block
87
87
  # whenever a message is received, passing the exact object that was sent from the server.
88
- def self.run(options={}, &block)
89
- new(options).run(&block)
88
+ # Never returns.
89
+ def self.start(options={}, &block)
90
+ new(options).start(&block)
90
91
  end
91
92
 
93
+
92
94
  module Unit
93
95
  attr_writer :gongren_header
94
96
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gongren
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - "Fran\xC3\xA7ois Beausoleil"
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2010-01-16 00:00:00 -05:00
12
+ date: 2010-01-20 00:00:00 -05:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -112,3 +112,7 @@ summary: Gongren distributes jobs to workers, with support for failed worker dae
112
112
  test_files:
113
113
  - test/helper.rb
114
114
  - test/test_gongren.rb
115
+ - examples/clock/consumer.rb
116
+ - examples/clock/producer.rb
117
+ - examples/faster_clock/consumer.rb
118
+ - examples/faster_clock/producer.rb