derfred-workling 0.4.9.1 → 0.4.9.2
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/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:
|