magent 0.6.2 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile +5 -4
- data/Gemfile.lock +21 -21
- data/Rakefile +4 -3
- data/VERSION +1 -1
- data/bin/magent +1 -3
- data/examples/findable.rb +36 -0
- data/examples/retries.rb +25 -0
- data/examples/test_mode.rb +20 -0
- data/lib/magent.rb +13 -7
- data/lib/magent/async.rb +16 -19
- data/lib/magent/async_channel.rb +10 -18
- data/lib/magent/failure.rb +12 -3
- data/lib/magent/generic_channel.rb +46 -1
- data/lib/magent/processor.rb +10 -10
- data/lib/magent/railtie.rb +1 -1
- data/lib/{tasks/magent.rake → magent/tasks.rb} +13 -10
- data/magent.gemspec +24 -33
- metadata +96 -147
- data/examples/comm/run.rb +0 -22
- data/examples/comm/worker.rb +0 -30
- data/examples/error/error.rb +0 -33
- data/examples/mongomapper/async.rb +0 -41
- data/examples/simple/bot.rb +0 -38
- data/examples/stats/stats.rb +0 -27
- data/lib/magent/actor.rb +0 -82
- data/lib/magent/actor_channel.rb +0 -34
- data/lib/magent/push.rb +0 -13
- data/lib/magent/web_socket_channel.rb +0 -16
- data/lib/magent/web_socket_server.rb +0 -107
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,34 +1,34 @@
|
|
1
1
|
GEM
|
2
2
|
remote: http://rubygems.org/
|
3
3
|
specs:
|
4
|
-
addressable (2.2.
|
5
|
-
bson (1.
|
6
|
-
|
7
|
-
em-websocket (0.1.4)
|
4
|
+
addressable (2.2.7)
|
5
|
+
bson (1.6.2)
|
6
|
+
em-websocket (0.3.6)
|
8
7
|
addressable (>= 2.1.1)
|
9
8
|
eventmachine (>= 0.12.9)
|
10
9
|
eventmachine (0.12.10)
|
11
|
-
haml (3.1.
|
12
|
-
launchy (
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
rack (1.
|
18
|
-
|
19
|
-
sinatra (1.2
|
20
|
-
rack (~> 1.1)
|
21
|
-
|
22
|
-
|
23
|
-
|
10
|
+
haml (3.1.4)
|
11
|
+
launchy (2.1.0)
|
12
|
+
addressable (~> 2.2.6)
|
13
|
+
mongo (1.6.2)
|
14
|
+
bson (~> 1.6.2)
|
15
|
+
rack (1.4.1)
|
16
|
+
rack-protection (1.2.0)
|
17
|
+
rack
|
18
|
+
sinatra (1.3.2)
|
19
|
+
rack (~> 1.3, >= 1.3.6)
|
20
|
+
rack-protection (~> 1.2)
|
21
|
+
tilt (~> 1.3, >= 1.3.3)
|
22
|
+
tilt (1.3.3)
|
23
|
+
uuidtools (2.1.2)
|
24
24
|
|
25
25
|
PLATFORMS
|
26
26
|
ruby
|
27
27
|
|
28
28
|
DEPENDENCIES
|
29
29
|
em-websocket
|
30
|
-
haml
|
31
|
-
launchy
|
32
|
-
mongo
|
33
|
-
sinatra
|
30
|
+
haml
|
31
|
+
launchy
|
32
|
+
mongo
|
33
|
+
sinatra
|
34
34
|
uuidtools
|
data/Rakefile
CHANGED
@@ -1,6 +1,9 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'rake'
|
3
3
|
|
4
|
+
$:.unshift File.expand_path("../lib", __FILE__)
|
5
|
+
require 'magent'
|
6
|
+
|
4
7
|
begin
|
5
8
|
require 'jeweler'
|
6
9
|
Jeweler::Tasks.new do |gem|
|
@@ -40,11 +43,9 @@ rescue LoadError
|
|
40
43
|
end
|
41
44
|
end
|
42
45
|
|
43
|
-
task :test => :check_dependencies
|
44
|
-
|
45
46
|
task :default => :test
|
46
47
|
|
47
|
-
require '
|
48
|
+
require 'rdoc/task'
|
48
49
|
Rake::RDocTask.new do |rdoc|
|
49
50
|
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
50
51
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.7.0
|
data/bin/magent
CHANGED
@@ -98,9 +98,7 @@ class Controller
|
|
98
98
|
def stop
|
99
99
|
begin
|
100
100
|
pid = File.read(pid_file).to_i
|
101
|
-
Process.kill("
|
102
|
-
Process.kill(0, pid)
|
103
|
-
Process.wait
|
101
|
+
Process.kill("QUIT", pid)
|
104
102
|
rescue Errno::ECHILD, Errno::ESRCH => e
|
105
103
|
$stdout.puts "Process #{pid} has stopped"
|
106
104
|
rescue Errno::ENOENT => e
|
@@ -0,0 +1,36 @@
|
|
1
|
+
$:.unshift File.expand_path("../../lib", __FILE__)
|
2
|
+
|
3
|
+
require 'magent'
|
4
|
+
|
5
|
+
class Findable
|
6
|
+
attr_accessor :id
|
7
|
+
def initialize(id)
|
8
|
+
@id = id
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.find(id)
|
12
|
+
Findable.new(id)
|
13
|
+
end
|
14
|
+
|
15
|
+
def inspect
|
16
|
+
"Findable<#{@id}>"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class Manager
|
21
|
+
include Magent::Async
|
22
|
+
|
23
|
+
def self.process(findable)
|
24
|
+
puts ">>> Proccessing: #{findable.inspect}"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
findable = Findable.new(19)
|
29
|
+
Manager.async(:queue1).process(findable)
|
30
|
+
|
31
|
+
|
32
|
+
# open the queue1 and process the messages
|
33
|
+
channel = Magent::AsyncChannel.new(:queue1)
|
34
|
+
processor = Magent::Processor.new(channel)
|
35
|
+
|
36
|
+
processor.run!(false)
|
data/examples/retries.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
$:.unshift File.expand_path("../../lib", __FILE__)
|
2
|
+
|
3
|
+
require 'magent'
|
4
|
+
|
5
|
+
class Worker
|
6
|
+
include Magent::Async
|
7
|
+
|
8
|
+
def self.work()
|
9
|
+
if rand < 0.95
|
10
|
+
puts "failed!"
|
11
|
+
raise "try again"
|
12
|
+
else
|
13
|
+
puts "OK!"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
Worker.async(:queue1).work
|
18
|
+
|
19
|
+
|
20
|
+
# open the queue1 and process the messages
|
21
|
+
channel = Magent::AsyncChannel.new(:queue1)
|
22
|
+
processor = Magent::Processor.new(channel)
|
23
|
+
|
24
|
+
processor.run!(true)
|
25
|
+
|
@@ -0,0 +1,20 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$:.unshift File.expand_path("../../lib", __FILE__)
|
4
|
+
|
5
|
+
require 'magent'
|
6
|
+
|
7
|
+
class MyClass
|
8
|
+
include Magent::Async
|
9
|
+
|
10
|
+
def foo
|
11
|
+
puts "bar"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
Magent.sync_mode = true
|
16
|
+
|
17
|
+
c = MyClass.new
|
18
|
+
c.async.foo
|
19
|
+
|
20
|
+
|
data/lib/magent.rb
CHANGED
@@ -11,18 +11,16 @@ require 'magent/failure'
|
|
11
11
|
|
12
12
|
require 'magent/utils'
|
13
13
|
require 'magent/generic_channel'
|
14
|
-
|
15
|
-
require 'magent/push'
|
16
|
-
require 'magent/actor'
|
14
|
+
|
17
15
|
require 'magent/processor'
|
18
16
|
|
19
17
|
require 'magent/async'
|
20
18
|
require 'magent/async_channel'
|
21
19
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
require 'magent/
|
20
|
+
if defined?(Rails) && Rails.version >= "3.0.0"
|
21
|
+
require 'magent/railtie'
|
22
|
+
elsif defined?(Rake)
|
23
|
+
require 'magent/tasks'
|
26
24
|
end
|
27
25
|
|
28
26
|
module Magent
|
@@ -62,6 +60,14 @@ module Magent
|
|
62
60
|
@@config = config
|
63
61
|
end
|
64
62
|
|
63
|
+
def self.sync_mode
|
64
|
+
@@sync_mode ||= false
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.sync_mode=(m)
|
68
|
+
@@sync_mode = m
|
69
|
+
end
|
70
|
+
|
65
71
|
def self.connect(environment, options={})
|
66
72
|
raise 'Set config before connecting. Magent.config = {...}' if config.nil? || config.empty?
|
67
73
|
|
data/lib/magent/async.rb
CHANGED
@@ -9,9 +9,9 @@
|
|
9
9
|
# end
|
10
10
|
#
|
11
11
|
# async call:
|
12
|
-
# Processor.find(id).async(:my_queue).process
|
12
|
+
# Processor.find(id).async(:my_queue, priority).process
|
13
13
|
# chained methods:
|
14
|
-
# Processor.async(:my_queue,
|
14
|
+
# Processor.async(:my_queue, priority).find(1).process
|
15
15
|
#
|
16
16
|
|
17
17
|
module Magent
|
@@ -26,39 +26,36 @@ module Magent
|
|
26
26
|
class Proxy
|
27
27
|
instance_methods.each { |m| undef_method m unless m =~ /(^__|^nil\?$|^send$|proxy_|^object_id$)/ }
|
28
28
|
|
29
|
-
def initialize(queue, target,
|
29
|
+
def initialize(queue, target, priority = 3)
|
30
30
|
@queue = queue
|
31
|
-
@method_chain = []
|
32
31
|
@target = target
|
33
|
-
@
|
32
|
+
@priority = priority
|
34
33
|
|
35
34
|
@channel = Magent::AsyncChannel.new(@queue)
|
36
35
|
end
|
37
36
|
|
38
|
-
def commit!(
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
target
|
43
|
-
@method_chain.each do |c|
|
44
|
-
target = target.send(c[0], *c[1])
|
45
|
-
end
|
46
|
-
|
47
|
-
target
|
37
|
+
def commit!(method_name, args)
|
38
|
+
if Magent.sync_mode
|
39
|
+
@target.send(method_name, *args)
|
40
|
+
else
|
41
|
+
@channel.push(@target, [method_name, args], @priority)
|
48
42
|
end
|
43
|
+
|
44
|
+
@target
|
49
45
|
end
|
50
46
|
|
51
47
|
def method_missing(m, *args, &blk)
|
52
48
|
raise ArgumentError, "ruby blocks are not supported yet" if !blk.nil?
|
53
|
-
|
49
|
+
|
50
|
+
commit!(m, args)
|
54
51
|
self
|
55
52
|
end
|
56
53
|
end
|
57
54
|
|
58
55
|
module Methods
|
59
|
-
# @question.async(:judge).on_view_question
|
60
|
-
def async(queue = :default,
|
61
|
-
Magent::Async::Proxy.new(queue, self,
|
56
|
+
# @question.async(:judge).on_view_question
|
57
|
+
def async(queue = :default, priority = 3)
|
58
|
+
Magent::Async::Proxy.new(queue, self, priority)
|
62
59
|
end
|
63
60
|
end
|
64
61
|
end # Async
|
data/lib/magent/async_channel.rb
CHANGED
@@ -1,38 +1,30 @@
|
|
1
1
|
module Magent
|
2
2
|
class AsyncChannel < GenericChannel
|
3
|
-
def push(target,
|
3
|
+
def push(target, method, priority)
|
4
|
+
encode_args(method[1])
|
5
|
+
|
4
6
|
if target.kind_of?(Class)
|
5
|
-
enqueue([target.to_s, nil,
|
7
|
+
enqueue([target.to_s, nil, method], priority)
|
6
8
|
elsif target.class.respond_to?(:find) && target.respond_to?(:id)
|
7
|
-
enqueue([target.class.to_s, target.id,
|
9
|
+
enqueue([target.class.to_s, target.id, method], priority)
|
8
10
|
else
|
9
11
|
raise ArgumentError, "I don't know how to handle #{target.inspect}"
|
10
12
|
end
|
11
13
|
end
|
12
14
|
|
13
15
|
def process!(message)
|
14
|
-
klass, id,
|
16
|
+
klass, id, method = message
|
15
17
|
|
16
|
-
return false if
|
18
|
+
return false if method.nil?
|
17
19
|
|
18
|
-
target =
|
20
|
+
target = async_find(klass, id)
|
21
|
+
args = resolve_args(method[1])
|
19
22
|
|
20
|
-
|
21
|
-
target = target.send(c[0], *c[1])
|
22
|
-
end
|
23
|
+
target = target.send(method[0], *args)
|
23
24
|
|
24
25
|
true
|
25
26
|
end
|
26
27
|
|
27
28
|
private
|
28
|
-
def resolve_target(klass, id)
|
29
|
-
klass = Object.module_eval(klass) if klass.kind_of?(String)
|
30
|
-
|
31
|
-
if id
|
32
|
-
klass.find(id)
|
33
|
-
else
|
34
|
-
klass
|
35
|
-
end
|
36
|
-
end
|
37
29
|
end # AsyncChannel
|
38
30
|
end
|
data/lib/magent/failure.rb
CHANGED
@@ -1,7 +1,12 @@
|
|
1
1
|
module Magent
|
2
2
|
module Failure
|
3
3
|
def failed(info)
|
4
|
-
error_collection.save(info.merge({
|
4
|
+
error_collection.save(info.merge({
|
5
|
+
:_id => generate_uid,
|
6
|
+
:channel => @name,
|
7
|
+
:channel_class => self.class.to_s,
|
8
|
+
:created_at => Time.now.utc
|
9
|
+
}))
|
5
10
|
end
|
6
11
|
|
7
12
|
def error_count
|
@@ -22,8 +27,12 @@ module Magent
|
|
22
27
|
end
|
23
28
|
|
24
29
|
def retry_error(error)
|
25
|
-
|
26
|
-
|
30
|
+
begin
|
31
|
+
process!(error["message"])
|
32
|
+
remove_error(error["_id"])
|
33
|
+
rescue => e
|
34
|
+
$stderr.puts "Failed to retry error #{error['_id']}: #{e.message}"
|
35
|
+
end
|
27
36
|
end
|
28
37
|
|
29
38
|
def enqueue_error(error)
|
@@ -11,7 +11,7 @@ module Magent
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def enqueue(message, priority = 3)
|
14
|
-
collection.save({:_id => generate_uid, :message => message, :priority => priority, :created_at => Time.now.to_i})
|
14
|
+
collection.save({:_id => generate_uid, :message => message, :priority => priority, :created_at => Time.now.to_i, :retries => 0})
|
15
15
|
end
|
16
16
|
|
17
17
|
def message_count
|
@@ -37,9 +37,54 @@ module Magent
|
|
37
37
|
@collection ||= Magent.database.collection(@name)
|
38
38
|
end
|
39
39
|
|
40
|
+
def retry_current_job
|
41
|
+
return false if !@current_job
|
42
|
+
|
43
|
+
@current_job['retries'] ||= 0
|
44
|
+
if @current_job['retries'] < 20
|
45
|
+
@current_job['retries'] += 1
|
46
|
+
collection.save(@current_job)
|
47
|
+
true
|
48
|
+
else
|
49
|
+
false
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
40
53
|
protected
|
41
54
|
def generate_uid
|
42
55
|
UUIDTools::UUID.random_create.hexdigest
|
43
56
|
end
|
57
|
+
|
58
|
+
def async_find(klass, id)
|
59
|
+
klass = Object.module_eval(klass) if klass.kind_of?(String)
|
60
|
+
|
61
|
+
if id
|
62
|
+
klass.find(id)
|
63
|
+
else
|
64
|
+
klass
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def encode_args(args)
|
69
|
+
args.map! do |arg|
|
70
|
+
if arg.class.respond_to?(:find) && arg.respond_to?(:id)
|
71
|
+
{'async_find' => [arg.class.to_s, arg.id]}
|
72
|
+
elsif arg.kind_of?(Class)
|
73
|
+
{'async_find' => [arg.to_s, nil]}
|
74
|
+
else
|
75
|
+
arg
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def resolve_args(args)
|
81
|
+
args.map do |arg|
|
82
|
+
if arg.kind_of?(Hash) && arg.include?('async_find')
|
83
|
+
async_find(*arg['async_find'])
|
84
|
+
else
|
85
|
+
arg
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
44
89
|
end # GenericChannel
|
45
90
|
end
|
data/lib/magent/processor.rb
CHANGED
@@ -6,15 +6,9 @@ module Magent
|
|
6
6
|
@identity = identity
|
7
7
|
|
8
8
|
@channel.on_start(identity)
|
9
|
-
|
10
|
-
# @actor.class.actions.each do |action|
|
11
|
-
# if !@actor.respond_to?(action)
|
12
|
-
# raise ArgumentError, "action '#{action}' is not defined"
|
13
|
-
# end
|
14
|
-
# end
|
15
9
|
end
|
16
10
|
|
17
|
-
def run!
|
11
|
+
def run!(service = true)
|
18
12
|
processed_messages = 0
|
19
13
|
delay = 0
|
20
14
|
|
@@ -43,19 +37,25 @@ module Magent
|
|
43
37
|
end
|
44
38
|
rescue SystemExit
|
45
39
|
rescue Exception => e
|
46
|
-
$stderr.puts "Error processing #{message.inspect} => #{e.message}"
|
40
|
+
$stderr.puts "Error processing #{message.inspect} => #{e.message}.\n#{e.backtrace.join("\n\t")}"
|
47
41
|
@channel.on_job_failed(@identity)
|
48
|
-
|
42
|
+
|
43
|
+
if !@channel.retry_current_job
|
44
|
+
$stderr.puts "Cannot retry job because it has been retried #{@channel.current_job['retries']} times"
|
45
|
+
@channel.failed(:error => e.message, :message => message, :backtrace => e.backtrace, :date => Time.now.utc)
|
46
|
+
end
|
49
47
|
ensure
|
50
48
|
end
|
51
49
|
|
50
|
+
break if !service
|
51
|
+
|
52
52
|
sleep (delay*100.0).to_i/100.0
|
53
53
|
end
|
54
54
|
end
|
55
55
|
|
56
56
|
def shutdown!
|
57
57
|
@shutdown = true
|
58
|
-
@channel.on_quit
|
58
|
+
@channel.on_quit(@identity)
|
59
59
|
|
60
60
|
@channel.on_shutdown if @channel.respond_to?(:on_shutdown)
|
61
61
|
$stderr.puts "Shutting down..."
|