derfred-workling 0.4.9.1 → 0.4.9.2
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/cattr_accessor.rb +51 -0
- data/lib/mattr_accessor.rb +55 -0
- data/lib/rude_q/client.rb +11 -0
- data/lib/workling/base.rb +115 -0
- data/lib/workling/clients/amqp_client.rb +38 -0
- data/lib/workling/clients/amqp_exchange_client.rb +50 -0
- data/lib/workling/clients/base.rb +57 -0
- data/lib/workling/clients/memcache_queue_client.rb +91 -0
- data/lib/workling/clients/sqs_client.rb +162 -0
- data/lib/workling/clients/xmpp_client.rb +100 -0
- data/lib/workling/discovery.rb +16 -0
- data/lib/workling/remote/invokers/amqp_single_subscriber.rb +45 -0
- data/lib/workling/remote/invokers/base.rb +124 -0
- data/lib/workling/remote/invokers/basic_poller.rb +41 -0
- data/lib/workling/remote/invokers/eventmachine_subscriber.rb +41 -0
- data/lib/workling/remote/invokers/looped_subscriber.rb +38 -0
- data/lib/workling/remote/invokers/thread_pool_poller.rb +169 -0
- data/lib/workling/remote/invokers/threaded_poller.rb +153 -0
- data/lib/workling/remote/runners/amqp_exchange_runner.rb +45 -0
- data/lib/workling/remote/runners/backgroundjob_runner.rb +35 -0
- data/lib/workling/remote/runners/base.rb +42 -0
- data/lib/workling/remote/runners/client_runner.rb +46 -0
- data/lib/workling/remote/runners/not_remote_runner.rb +23 -0
- data/lib/workling/remote/runners/not_runner.rb +17 -0
- data/lib/workling/remote/runners/rudeq_runner.rb +23 -0
- data/lib/workling/remote/runners/spawn_runner.rb +38 -0
- data/lib/workling/remote/runners/starling_runner.rb +13 -0
- data/lib/workling/remote.rb +69 -0
- data/lib/workling/return/store/base.rb +42 -0
- data/lib/workling/return/store/iterator.rb +24 -0
- data/lib/workling/return/store/memory_return_store.rb +26 -0
- data/lib/workling/return/store/rudeq_return_store.rb +24 -0
- data/lib/workling/return/store/starling_return_store.rb +31 -0
- data/lib/workling/routing/base.rb +16 -0
- data/lib/workling/routing/class_and_method_routing.rb +57 -0
- data/lib/workling/routing/static_routing.rb +47 -0
- data/lib/workling/rudeq/client.rb +17 -0
- data/lib/workling/rudeq/poller.rb +116 -0
- data/lib/workling/rudeq.rb +7 -0
- data/lib/workling.rb +195 -0
- data/lib/workling_server.rb +108 -0
- data/script/bj_invoker.rb +11 -0
- data/script/starling_status.rb +37 -0
- metadata +44 -1
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'workling/routing/base'
|
2
|
+
|
3
|
+
#
|
4
|
+
# Holds a hash of routes. Each Worker method has a corresponding hash entry after building.
|
5
|
+
#
|
6
|
+
module Workling
|
7
|
+
module Routing
|
8
|
+
class ClassAndMethodRouting < Base
|
9
|
+
|
10
|
+
# initializes and builds routing hash.
|
11
|
+
def initialize(*args)
|
12
|
+
super
|
13
|
+
|
14
|
+
build
|
15
|
+
end
|
16
|
+
|
17
|
+
# returns the worker method name, given the routing string.
|
18
|
+
def method_name(queue)
|
19
|
+
self[queue].method_for(queue)
|
20
|
+
end
|
21
|
+
|
22
|
+
# returns the routing string, given a class and method. delegating.
|
23
|
+
def queue_for(clazz, method)
|
24
|
+
ClassAndMethodRouting.queue_for(clazz, method)
|
25
|
+
end
|
26
|
+
|
27
|
+
# returns the routing string, given a class and method.
|
28
|
+
def self.queue_for(clazz, method)
|
29
|
+
# this is lifted from the Rails constantize method
|
30
|
+
clazz = Object.module_eval("::#{clazz}") unless clazz.is_a?(Class)
|
31
|
+
clazz.queue_for method
|
32
|
+
end
|
33
|
+
|
34
|
+
# returns all routed
|
35
|
+
def queue_names
|
36
|
+
self.keys
|
37
|
+
end
|
38
|
+
|
39
|
+
# dare you to remove this! go on!
|
40
|
+
def queue_names_routing_class(clazz)
|
41
|
+
self.select { |x, y| y.is_a?(clazz) }.map { |x, y| x }
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
def build
|
46
|
+
Workling::Discovery.discovered.each do |clazz|
|
47
|
+
methods = clazz.public_instance_methods(false)
|
48
|
+
methods.each do |method|
|
49
|
+
next if method == 'create' # Skip the create method
|
50
|
+
queue = queue_for(clazz, method)
|
51
|
+
self[queue] = clazz.new
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'workling/routing/base'
|
2
|
+
|
3
|
+
#
|
4
|
+
# Holds a single route for a dedicated worker (if you want more worker processes, run more workers)
|
5
|
+
#
|
6
|
+
module Workling
|
7
|
+
module Routing
|
8
|
+
class StaticRouting < Base
|
9
|
+
|
10
|
+
#
|
11
|
+
# ./script/workling_client run -- <worker_class> <worker_method> <routing_key>
|
12
|
+
# ./script/workling_client run -- <worker_class> <worker_method> <routing_key> <queue_name>
|
13
|
+
#
|
14
|
+
def initialize(*args)
|
15
|
+
@worker = args[0].constantize.new
|
16
|
+
@method_name = args[1]
|
17
|
+
@routing_key = args[2]
|
18
|
+
|
19
|
+
if(args.size==4)
|
20
|
+
@queue_name = args[3]
|
21
|
+
else
|
22
|
+
@queue_name = [@worker.class.to_s.tableize, @method_name, @routing_key].join("__")
|
23
|
+
end
|
24
|
+
|
25
|
+
# so routing[x] hash access works as expected
|
26
|
+
self.default = @worker
|
27
|
+
|
28
|
+
puts "** static routing: queue - #{@queue_name}, routing_key - #{@routing_key}, method - #{@method_name}, worker - #{@worker.class}"
|
29
|
+
end
|
30
|
+
|
31
|
+
# returns the worker method name, given the routing string.
|
32
|
+
def method_name(queue=nil); @method_name; end
|
33
|
+
|
34
|
+
def routing_key_for; @routing_key; end
|
35
|
+
|
36
|
+
# returns the routing string, given a class and method. delegating.
|
37
|
+
# TODO - we can check for consistency here with clazz and methods vs. current configuration of this single route
|
38
|
+
def queue_for(clazz=nil, method=nil); @queue_name; end
|
39
|
+
|
40
|
+
# returns array containing the single configured route
|
41
|
+
def queue_names; [@queue_name]; end
|
42
|
+
|
43
|
+
# TODO - not sure what this is...
|
44
|
+
def queue_names_routing_class(clazz); @worker.class; end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'workling/rudeq'
|
2
|
+
|
3
|
+
module Workling
|
4
|
+
module Rudeq
|
5
|
+
class Client
|
6
|
+
attr_reader :queue
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@queue = Workling::Rudeq.config[:queue_class].constantize
|
10
|
+
end
|
11
|
+
|
12
|
+
def method_missing(method, *args)
|
13
|
+
@queue.send(method, *args)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
require 'workling/rudeq'
|
2
|
+
|
3
|
+
module Workling
|
4
|
+
module Rudeq
|
5
|
+
|
6
|
+
class Poller
|
7
|
+
|
8
|
+
cattr_accessor :sleep_time # Seconds to sleep before looping
|
9
|
+
cattr_accessor :reset_time # Seconds to wait while resetting connection
|
10
|
+
|
11
|
+
def initialize(routing)
|
12
|
+
Poller.sleep_time = Workling::Rudeq.config[:sleep_time] || 2
|
13
|
+
Poller.reset_time = Workling::Rudeq.config[:reset_time] || 30
|
14
|
+
|
15
|
+
@routing = routing
|
16
|
+
@workers = ThreadGroup.new
|
17
|
+
end
|
18
|
+
|
19
|
+
def logger
|
20
|
+
Workling::Base.logger
|
21
|
+
end
|
22
|
+
|
23
|
+
def listen
|
24
|
+
|
25
|
+
# Allow concurrency for our tasks
|
26
|
+
ActiveRecord::Base.allow_concurrency = true
|
27
|
+
|
28
|
+
# Create a thread for each worker.
|
29
|
+
Workling::Discovery.discovered.each do |clazz|
|
30
|
+
logger.debug("Discovered listener #{clazz}")
|
31
|
+
@workers.add(Thread.new(clazz) { |c| clazz_listen(c) })
|
32
|
+
end
|
33
|
+
|
34
|
+
# Wait for all workers to complete
|
35
|
+
@workers.list.each { |t| t.join }
|
36
|
+
|
37
|
+
# Clean up all the connections.
|
38
|
+
ActiveRecord::Base.verify_active_connections!
|
39
|
+
end
|
40
|
+
|
41
|
+
# gracefully stop processing
|
42
|
+
def stop
|
43
|
+
@workers.list.each { |w| w[:shutdown] = true }
|
44
|
+
end
|
45
|
+
|
46
|
+
##
|
47
|
+
## Thread procs
|
48
|
+
##
|
49
|
+
|
50
|
+
# Listen for one worker class
|
51
|
+
def clazz_listen(clazz)
|
52
|
+
|
53
|
+
logger.debug("Listener thread #{clazz.name} started")
|
54
|
+
|
55
|
+
# Read thread configuration if available
|
56
|
+
if Rudeq.config.has_key?(:listeners)
|
57
|
+
if Rudeq.config[:listeners].has_key?(clazz.to_s)
|
58
|
+
config = Rudeq.config[:listeners][clazz.to_s].symbolize_keys
|
59
|
+
thread_sleep_time = config[:sleep_time] if config.has_key?(:sleep_time)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
hread_sleep_time ||= self.class.sleep_time
|
64
|
+
|
65
|
+
connection = Workling::Rudeq::Client.new
|
66
|
+
puts "** Starting Workling::Rudeq::Client for #{clazz.name} queue"
|
67
|
+
|
68
|
+
# Start dispatching those messages
|
69
|
+
while (!Thread.current[:shutdown]) do
|
70
|
+
begin
|
71
|
+
|
72
|
+
# Keep MySQL connection alive
|
73
|
+
unless ActiveRecord::Base.connection.active?
|
74
|
+
unless ActiveRecord::Base.connection.reconnect!
|
75
|
+
logger.fatal("FAILED - Database not available")
|
76
|
+
break
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# Dispatch and process the messages
|
81
|
+
n = dispatch!(connection, clazz)
|
82
|
+
logger.debug("Listener thread #{clazz.name} processed #{n.to_s} queue items") if n > 0
|
83
|
+
sleep(self.class.sleep_time) unless n > 0
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
logger.debug("Listener thread #{clazz.name} ended")
|
88
|
+
end
|
89
|
+
|
90
|
+
# Dispatcher for one worker class.
|
91
|
+
# Returns the number of worker methods called
|
92
|
+
def dispatch!(connection, clazz)
|
93
|
+
n = 0
|
94
|
+
for queue in @routing.queue_names_routing_class(clazz)
|
95
|
+
begin
|
96
|
+
result = connection.get(queue)
|
97
|
+
if result
|
98
|
+
n += 1
|
99
|
+
handler = @routing[queue]
|
100
|
+
method_name = @routing.method_name(queue)
|
101
|
+
logger.debug("Calling #{handler.class.to_s}\##{method_name}(#{result.inspect})")
|
102
|
+
handler.send(method_name, result)
|
103
|
+
end
|
104
|
+
rescue
|
105
|
+
logger.error("FAILED to connect with queue #{ queue }: #{ e } }")
|
106
|
+
raise e
|
107
|
+
rescue Object => e
|
108
|
+
logger.error("FAILED to process queue #{ queue }. #{ @routing[queue] } could not handle invocation of #{ @routing.method_name(queue) } with #{ result.inspect }: #{ e }.\n#{ e.backtrace.join("\n") }")
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
return n
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
data/lib/workling.rb
ADDED
@@ -0,0 +1,195 @@
|
|
1
|
+
#
|
2
|
+
# I can haz am in your Workling are belong to us!
|
3
|
+
#
|
4
|
+
require 'mattr_accessor' unless Module.respond_to?(:mattr_accessor)
|
5
|
+
require 'cattr_accessor' unless Class.respond_to?(:cattr_accessor)
|
6
|
+
|
7
|
+
gem 'activesupport'
|
8
|
+
require 'active_support/inflector'
|
9
|
+
require 'active_support/core_ext/hash/keys'
|
10
|
+
|
11
|
+
class Hash #:nodoc:
|
12
|
+
include ActiveSupport::CoreExtensions::Hash::Keys
|
13
|
+
end
|
14
|
+
|
15
|
+
require 'yaml'
|
16
|
+
|
17
|
+
module Workling
|
18
|
+
class WorklingError < StandardError; end
|
19
|
+
class WorklingNotFoundError < WorklingError; end
|
20
|
+
class WorklingConnectionError < WorklingError; end
|
21
|
+
class QueueserverNotFoundError < WorklingError
|
22
|
+
def initialize
|
23
|
+
super "config/workling.yml configured to connect to queue server on #{ Workling.config[:listens_on] } for this environment. could not connect to queue server on this host:port. for starling users: pass starling the port with -p flag when starting it. If you don't want to use Starling, then explicitly set Workling::Remote.dispatcher (see README for an example)"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class ConfigurationError < WorklingError
|
28
|
+
def initialize
|
29
|
+
super File.exist?(Workling.path('config', 'starling.yml')) ?
|
30
|
+
"config/starling.yml has been depracated. rename your config file to config/workling.yml then try again!" :
|
31
|
+
"config/workling.yml could not be loaded. check out README.markdown to see what this file should contain. "
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.path(*args)
|
36
|
+
if defined?(RAILS_ROOT)
|
37
|
+
File.join(RAILS_ROOT, *args)
|
38
|
+
else
|
39
|
+
File.join(Dir.pwd, *args)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.env
|
44
|
+
@env ||= if defined?(RAILS_ENV)
|
45
|
+
RAILS_ENV.to_s
|
46
|
+
elsif defined?(RACK_ENV)
|
47
|
+
RACK_ENV.to_s
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
mattr_accessor :load_path
|
52
|
+
@@load_path = [ File.expand_path(path('app', 'workers')) ]
|
53
|
+
|
54
|
+
VERSION = "0.4.9"
|
55
|
+
|
56
|
+
#
|
57
|
+
# determine the runner to use if nothing is specifically set. workling will try to detect
|
58
|
+
# starling, spawn, or bj, in that order. if none of these are found, notremoterunner will
|
59
|
+
# be used.
|
60
|
+
#
|
61
|
+
# this can be overridden by setting Workling::Remote.dispatcher, eg:
|
62
|
+
# Workling::Remote.dispatcher = Workling::Remote::Runners::StarlingRunner.new
|
63
|
+
#
|
64
|
+
def self.default_runner
|
65
|
+
if env == "test"
|
66
|
+
Workling::Remote::Runners::NotRemoteRunner.new
|
67
|
+
elsif starling_installed?
|
68
|
+
Workling::Remote::Runners::StarlingRunner.new
|
69
|
+
elsif spawn_installed?
|
70
|
+
Workling::Remote::Runners::SpawnRunner.new
|
71
|
+
elsif bj_installed?
|
72
|
+
Workling::Remote::Runners::BackgroundjobRunner.new
|
73
|
+
else
|
74
|
+
Workling::Remote::Runners::NotRemoteRunner.new
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
#
|
79
|
+
# gets the worker instance, given a class. the optional method argument will cause an
|
80
|
+
# exception to be raised if the worker instance does not respoind to said method.
|
81
|
+
#
|
82
|
+
def self.find(clazz, method = nil)
|
83
|
+
begin
|
84
|
+
inst = clazz.to_s.camelize.constantize.new
|
85
|
+
rescue NameError
|
86
|
+
raise_not_found(clazz, method)
|
87
|
+
end
|
88
|
+
raise_not_found(clazz, method) if method && !inst.respond_to?(method)
|
89
|
+
inst
|
90
|
+
end
|
91
|
+
|
92
|
+
# returns Workling::Return::Store.instance.
|
93
|
+
def self.return
|
94
|
+
Workling::Return::Store.instance
|
95
|
+
end
|
96
|
+
|
97
|
+
# is spawn installed?
|
98
|
+
def self.spawn_installed?
|
99
|
+
begin
|
100
|
+
require 'spawn'
|
101
|
+
rescue LoadError
|
102
|
+
end
|
103
|
+
|
104
|
+
Object.const_defined? "Spawn"
|
105
|
+
end
|
106
|
+
|
107
|
+
# is starling installed?
|
108
|
+
def self.starling_installed?
|
109
|
+
begin
|
110
|
+
require 'starling'
|
111
|
+
rescue LoadError
|
112
|
+
end
|
113
|
+
|
114
|
+
Object.const_defined? "Starling"
|
115
|
+
end
|
116
|
+
|
117
|
+
# is bj installed?
|
118
|
+
def self.bj_installed?
|
119
|
+
Object.const_defined? "Bj"
|
120
|
+
end
|
121
|
+
|
122
|
+
# Attempts to load the memcache-client gem
|
123
|
+
def self.try_load_a_memcache_client
|
124
|
+
begin
|
125
|
+
gem 'memcache-client'
|
126
|
+
require 'memcache'
|
127
|
+
rescue Gem::LoadError
|
128
|
+
Workling::Base.logger.info "WORKLING: couldn't find memcache-client. Install: \"gem install memcache-client\". "
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
# attempts to load amqp and writes out descriptive error message if not present
|
133
|
+
def self.try_load_an_amqp_client
|
134
|
+
begin
|
135
|
+
require 'mq'
|
136
|
+
rescue Exception => e
|
137
|
+
raise WorklingError.new(
|
138
|
+
"WORKLING: couldn't find the ruby amqp client - you need it for the amqp runner. " \
|
139
|
+
"Install from github: gem sources -a http://gems.github.com/ && sudo gem install tmm1-amqp "
|
140
|
+
)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
# attempts to load xmpp4r library and writes out descriptive error message if not present
|
145
|
+
def self.try_load_xmpp4r
|
146
|
+
begin
|
147
|
+
gem "xmpp4r"
|
148
|
+
require 'xmpp4r'
|
149
|
+
require "xmpp4r/pubsub"
|
150
|
+
require "xmpp4r/pubsub/helper/servicehelper.rb"
|
151
|
+
require "xmpp4r/pubsub/helper/nodebrowser.rb"
|
152
|
+
require "xmpp4r/pubsub/helper/nodehelper.rb"
|
153
|
+
rescue Exception => e
|
154
|
+
raise WorklingError.new("Couldnt load the XMPP library. check that you have the xmpp4r gem installed")
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
|
159
|
+
#
|
160
|
+
# returns a config hash. reads ./config/workling.yml
|
161
|
+
#
|
162
|
+
def self.config
|
163
|
+
return @@config if defined?(@@config) && @@config
|
164
|
+
|
165
|
+
config_path = File.join(RAILS_ROOT, 'config', 'workling.yml')
|
166
|
+
return nil unless File.exists?(config_path)
|
167
|
+
|
168
|
+
@@config ||= YAML.load_file(config_path)[RAILS_ENV || 'development'].symbolize_keys
|
169
|
+
@@config[:memcache_options].symbolize_keys! if @@config[:memcache_options]
|
170
|
+
@@config
|
171
|
+
end
|
172
|
+
|
173
|
+
#
|
174
|
+
# Raises exceptions thrown inside of the worker. normally, these are logged to
|
175
|
+
# logger.error. it's easy to miss these log calls while developing, though.
|
176
|
+
#
|
177
|
+
mattr_accessor :raise_exceptions
|
178
|
+
@@raise_exceptions = (RAILS_ENV == "test" || RAILS_ENV == "development")
|
179
|
+
|
180
|
+
def self.raise_exceptions?
|
181
|
+
@@raise_exceptions
|
182
|
+
end
|
183
|
+
|
184
|
+
private
|
185
|
+
def self.raise_not_found(clazz, method)
|
186
|
+
raise Workling::WorklingNotFoundError.new("could not find #{ clazz }:#{ method } workling. ")
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
require "workling/discovery"
|
191
|
+
require "workling/base"
|
192
|
+
require "workling/remote"
|
193
|
+
require "workling/return/store/base"
|
194
|
+
require "workling/return/store/memory_return_store"
|
195
|
+
require "workling/return/store/starling_return_store"
|
@@ -0,0 +1,108 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
|
3
|
+
class WorklingServer
|
4
|
+
@@in_server_mode = false
|
5
|
+
def self.in_server_mode
|
6
|
+
@@in_server_mode
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.in_server_mode=(server_mode)
|
10
|
+
@@in_server_mode = server_mode
|
11
|
+
end
|
12
|
+
|
13
|
+
|
14
|
+
def self.partition_options(args)
|
15
|
+
daemon = []
|
16
|
+
workling = []
|
17
|
+
split_point = args.index("--") || args.size
|
18
|
+
daemon = args[0...split_point] if split_point > 0
|
19
|
+
workling = args[(split_point+1)..-1] if split_point and split_point < args.size
|
20
|
+
[daemon, workling]
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.partition_daemons_options(args)
|
24
|
+
standard_options = %W{start stop restart run zap -t --ontop -f --force -h --help --version}
|
25
|
+
pass_through = args.select { |a| standard_options.include? a }
|
26
|
+
custom_options = args.reject { |a| standard_options.include? a }
|
27
|
+
|
28
|
+
[pass_through, custom_options]
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.parse_daemon_options(argv)
|
32
|
+
options = {}
|
33
|
+
pass_through, args = partition_daemons_options argv
|
34
|
+
opts = OptionParser.new do |opts|
|
35
|
+
opts.banner = 'Usage: myapp [options]'
|
36
|
+
opts.separator ''
|
37
|
+
opts.on('-a', '--app-name APP_NAME', String,"specify the process name") { |v| options[:app_name] = v }
|
38
|
+
opts.on('-d', '--dir DIR', String, "the directory to run in") { |v| options[:dir] = v }
|
39
|
+
opts.on('-m', '--monitor',"specify the process name") { |v| options[:monitor] = true }
|
40
|
+
opts.on('-t', '--ontop') { |k, v| pass_through << v }
|
41
|
+
end
|
42
|
+
opts.parse!(partition_options(args).first)
|
43
|
+
options.merge(:ARGV => pass_through)
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.parse_workling_options(args)
|
47
|
+
options = {}
|
48
|
+
opts = OptionParser.new do |opts|
|
49
|
+
opts.banner = 'Usage: myapp [options]'
|
50
|
+
opts.separator ''
|
51
|
+
opts.on('-c', '--client CLIENT', String,"specify the client class") { |v| options[:client_class] = v }
|
52
|
+
opts.on('-i', '--invoker INVOKER', String,"specify the invoker class") { |v| options[:invoker_class] = v }
|
53
|
+
opts.on('-r', '--routing ROUTING', String,"specify the routing class") { |v| options[:routing_class] = v }
|
54
|
+
opts.on('-l', '--load-path LOADPATH', String,"specify the load_path for the workers") { |v| options[:load_path] = v }
|
55
|
+
opts.on('-e', '--environment ENVIRONMENT', String,"specify the environment") { |v| options[:rails_env] = v }
|
56
|
+
end
|
57
|
+
opts.parse!(partition_options(args).last)
|
58
|
+
options
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
def self.build_poller(options)
|
63
|
+
require 'workling/remote'
|
64
|
+
["remote/invokers/*.rb", "routing/*.rb"].each do |pattern|
|
65
|
+
Dir.glob(pattern).each do |f|
|
66
|
+
require File.join(File.dirname(f), File.basename(f, ".rb"))
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
routing_class = Object.module_eval("::#{options[:routing_class]}")
|
71
|
+
client_class = Object.module_eval("::#{options[:client_class]}")
|
72
|
+
invoker_class = Object.module_eval("::#{options[:invoker_class]}")
|
73
|
+
invoker_class.new(routing_class.new, client_class)
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
def self.run(options)
|
78
|
+
WorklingServer.in_server_mode = true
|
79
|
+
|
80
|
+
ENV["RAILS_ENV"] = options[:rails_env]
|
81
|
+
puts "=> Loading Rails with #{ENV["RAILS_ENV"]} environment..."
|
82
|
+
|
83
|
+
require options[:rails_root] + '/config/environment'
|
84
|
+
|
85
|
+
Workling.load_path = options[:load_path]
|
86
|
+
|
87
|
+
Workling::Discovery.discover!
|
88
|
+
Workling.config
|
89
|
+
|
90
|
+
poller = build_poller options
|
91
|
+
|
92
|
+
puts '** Rails loaded.'
|
93
|
+
puts "** Starting #{ poller.class }..."
|
94
|
+
puts '** Use CTRL-C to stop.'
|
95
|
+
|
96
|
+
ActiveRecord::Base.logger = Workling::Base.logger
|
97
|
+
ActionController::Base.logger = Workling::Base.logger
|
98
|
+
|
99
|
+
trap(:INT) { poller.stop; exit }
|
100
|
+
|
101
|
+
begin
|
102
|
+
poller.listen
|
103
|
+
ensure
|
104
|
+
puts '** No Worklings found.' if Workling::Discovery.discovered.blank?
|
105
|
+
puts '** Exiting'
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
@routing = Workling::Routing::ClassAndMethodRouting.new
|
2
|
+
unnormalized = REXML::Text::unnormalize(STDIN.read)
|
3
|
+
message, command, args = *unnormalized.match(/(^[^ ]*) (.*)/)
|
4
|
+
options = Hash.from_xml(args)["hash"]
|
5
|
+
|
6
|
+
if workling = @routing[command]
|
7
|
+
options = options.symbolize_keys
|
8
|
+
method_name = @routing.method_name(command)
|
9
|
+
|
10
|
+
workling.dispatch_to_worker_method(method_name, options)
|
11
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'pp'
|
2
|
+
|
3
|
+
puts '=> Loading Rails...'
|
4
|
+
|
5
|
+
require File.dirname(__FILE__) + '/../config/environment'
|
6
|
+
require File.dirname(__FILE__) + '/../vendor/plugins/workling/lib/workling/remote/invokers/basic_poller'
|
7
|
+
require File.dirname(__FILE__) + '/../vendor/plugins/workling/lib/workling/routing/class_and_method_routing'
|
8
|
+
|
9
|
+
puts '** Rails loaded.'
|
10
|
+
|
11
|
+
trap(:INT) { exit }
|
12
|
+
|
13
|
+
client = Workling::Clients::MemcacheQueueClient.new
|
14
|
+
|
15
|
+
begin
|
16
|
+
client.connect
|
17
|
+
client.reset
|
18
|
+
|
19
|
+
client.stats # do this so that connection is shown as established below.
|
20
|
+
|
21
|
+
puts "Queue state:"
|
22
|
+
pp client.inspect
|
23
|
+
pp "Active?: #{client.active?}"
|
24
|
+
pp "Read Only?: #{client.readonly?}"
|
25
|
+
puts ""
|
26
|
+
puts "Servers:"
|
27
|
+
pp client.servers
|
28
|
+
puts ""
|
29
|
+
puts "Queue stats:"
|
30
|
+
pp client.stats
|
31
|
+
|
32
|
+
puts "\nThread Stats:"
|
33
|
+
pp Thread.list
|
34
|
+
ensure
|
35
|
+
puts '** Exiting'
|
36
|
+
client.close
|
37
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: derfred-workling
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.9.
|
4
|
+
version: 0.4.9.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rany Keddo
|
@@ -26,6 +26,49 @@ files:
|
|
26
26
|
- VERSION.yml
|
27
27
|
- README.markdown
|
28
28
|
- TODO.markdown
|
29
|
+
- lib/cattr_accessor.rb
|
30
|
+
- lib/mattr_accessor.rb
|
31
|
+
- lib/rude_q/client.rb
|
32
|
+
- lib/workling/base.rb
|
33
|
+
- lib/workling/clients/amqp_client.rb
|
34
|
+
- lib/workling/clients/amqp_exchange_client.rb
|
35
|
+
- lib/workling/clients/base.rb
|
36
|
+
- lib/workling/clients/memcache_queue_client.rb
|
37
|
+
- lib/workling/clients/sqs_client.rb
|
38
|
+
- lib/workling/clients/xmpp_client.rb
|
39
|
+
- lib/workling/discovery.rb
|
40
|
+
- lib/workling/remote/invokers/amqp_single_subscriber.rb
|
41
|
+
- lib/workling/remote/invokers/base.rb
|
42
|
+
- lib/workling/remote/invokers/basic_poller.rb
|
43
|
+
- lib/workling/remote/invokers/eventmachine_subscriber.rb
|
44
|
+
- lib/workling/remote/invokers/looped_subscriber.rb
|
45
|
+
- lib/workling/remote/invokers/thread_pool_poller.rb
|
46
|
+
- lib/workling/remote/invokers/threaded_poller.rb
|
47
|
+
- lib/workling/remote/runners/amqp_exchange_runner.rb
|
48
|
+
- lib/workling/remote/runners/backgroundjob_runner.rb
|
49
|
+
- lib/workling/remote/runners/base.rb
|
50
|
+
- lib/workling/remote/runners/client_runner.rb
|
51
|
+
- lib/workling/remote/runners/not_remote_runner.rb
|
52
|
+
- lib/workling/remote/runners/not_runner.rb
|
53
|
+
- lib/workling/remote/runners/rudeq_runner.rb
|
54
|
+
- lib/workling/remote/runners/spawn_runner.rb
|
55
|
+
- lib/workling/remote/runners/starling_runner.rb
|
56
|
+
- lib/workling/remote.rb
|
57
|
+
- lib/workling/return/store/base.rb
|
58
|
+
- lib/workling/return/store/iterator.rb
|
59
|
+
- lib/workling/return/store/memory_return_store.rb
|
60
|
+
- lib/workling/return/store/rudeq_return_store.rb
|
61
|
+
- lib/workling/return/store/starling_return_store.rb
|
62
|
+
- lib/workling/routing/base.rb
|
63
|
+
- lib/workling/routing/class_and_method_routing.rb
|
64
|
+
- lib/workling/routing/static_routing.rb
|
65
|
+
- lib/workling/rudeq/client.rb
|
66
|
+
- lib/workling/rudeq/poller.rb
|
67
|
+
- lib/workling/rudeq.rb
|
68
|
+
- lib/workling.rb
|
69
|
+
- lib/workling_server.rb
|
70
|
+
- script/bj_invoker.rb
|
71
|
+
- script/starling_status.rb
|
29
72
|
has_rdoc: true
|
30
73
|
homepage: http://github.com/elecnix/workling
|
31
74
|
post_install_message:
|