derfred-workling 0.4.9.2 → 0.4.9.3
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/bin/workling_client +9 -7
- data/{script → contrib}/bj_invoker.rb +0 -0
- data/{script → contrib}/starling_status.rb +0 -0
- data/lib/{cattr_accessor.rb → extensions/cattr_accessor.rb} +0 -0
- data/lib/{mattr_accessor.rb → extensions/mattr_accessor.rb} +0 -0
- data/lib/workling.rb +98 -94
- data/lib/workling/base.rb +6 -11
- data/lib/workling/clients/amqp_client.rb +13 -5
- data/lib/workling/clients/amqp_exchange_client.rb +19 -11
- data/lib/workling/clients/backgroundjob_client.rb +25 -0
- data/lib/workling/clients/base.rb +40 -8
- data/lib/workling/clients/broker_base.rb +63 -0
- data/lib/workling/clients/memcache_queue_client.rb +24 -12
- data/lib/workling/clients/memory_queue_client.rb +34 -0
- data/lib/workling/clients/not_client.rb +14 -0
- data/lib/workling/clients/not_remote_client.rb +17 -0
- data/lib/workling/clients/spawn_client.rb +47 -0
- data/lib/workling/clients/sqs_client.rb +9 -8
- data/lib/workling/clients/thread_client.rb +18 -0
- data/lib/workling/clients/xmpp_client.rb +14 -4
- data/lib/workling/discovery.rb +1 -1
- data/lib/workling/invokers/amqp_single_subscriber.rb +42 -0
- data/lib/workling/invokers/base.rb +124 -0
- data/lib/workling/invokers/basic_poller.rb +38 -0
- data/lib/workling/invokers/eventmachine_subscriber.rb +38 -0
- data/lib/workling/invokers/looped_subscriber.rb +34 -0
- data/lib/workling/invokers/thread_pool_poller.rb +165 -0
- data/lib/workling/invokers/threaded_poller.rb +149 -0
- data/lib/workling/remote.rb +10 -41
- data/lib/workling/return/store/base.rb +7 -7
- data/lib/workling/return/store/memory_return_store.rb +0 -2
- data/lib/workling/return/store/starling_return_store.rb +7 -8
- data/lib/workling/routing/base.rb +1 -4
- data/lib/workling/routing/class_and_method_routing.rb +0 -2
- data/lib/workling/routing/static_routing.rb +0 -4
- data/lib/{workling_server.rb → workling_daemon.rb} +27 -25
- metadata +21 -28
- data/lib/rude_q/client.rb +0 -11
- data/lib/workling/remote/invokers/amqp_single_subscriber.rb +0 -45
- data/lib/workling/remote/invokers/base.rb +0 -124
- data/lib/workling/remote/invokers/basic_poller.rb +0 -41
- data/lib/workling/remote/invokers/eventmachine_subscriber.rb +0 -41
- data/lib/workling/remote/invokers/looped_subscriber.rb +0 -38
- data/lib/workling/remote/invokers/thread_pool_poller.rb +0 -169
- data/lib/workling/remote/invokers/threaded_poller.rb +0 -153
- data/lib/workling/remote/runners/amqp_exchange_runner.rb +0 -45
- data/lib/workling/remote/runners/backgroundjob_runner.rb +0 -35
- data/lib/workling/remote/runners/base.rb +0 -42
- data/lib/workling/remote/runners/client_runner.rb +0 -46
- data/lib/workling/remote/runners/not_remote_runner.rb +0 -23
- data/lib/workling/remote/runners/not_runner.rb +0 -17
- data/lib/workling/remote/runners/rudeq_runner.rb +0 -23
- data/lib/workling/remote/runners/spawn_runner.rb +0 -38
- data/lib/workling/remote/runners/starling_runner.rb +0 -13
- data/lib/workling/return/store/rudeq_return_store.rb +0 -24
- data/lib/workling/rudeq.rb +0 -7
- data/lib/workling/rudeq/client.rb +0 -17
- data/lib/workling/rudeq/poller.rb +0 -116
@@ -1,35 +0,0 @@
|
|
1
|
-
require 'workling/remote/runners/base'
|
2
|
-
|
3
|
-
#
|
4
|
-
# Use Ara Howards BackgroundJob to run the work. BackgroundJob loads Rails once per requested Job.
|
5
|
-
# It persists over the database, and there is no requirement for separate processes to be started.
|
6
|
-
# Since rails has to load before each request, it takes a moment for the job to run.
|
7
|
-
#
|
8
|
-
module Workling
|
9
|
-
module Remote
|
10
|
-
module Runners
|
11
|
-
class BackgroundjobRunner < Workling::Remote::Runners::Base
|
12
|
-
cattr_accessor :routing
|
13
|
-
|
14
|
-
def initialize
|
15
|
-
BackgroundjobRunner.routing =
|
16
|
-
Workling::Routing::ClassAndMethodRouting.new
|
17
|
-
end
|
18
|
-
|
19
|
-
# passes the job to bj by serializing the options to xml and passing them to
|
20
|
-
# ./script/bj_invoker.rb, which in turn routes the deserialized args to the
|
21
|
-
# appropriate worker.
|
22
|
-
def run(clazz, method, options = {})
|
23
|
-
stdin = @@routing.queue_for(clazz, method) +
|
24
|
-
" " +
|
25
|
-
options.to_xml(:indent => 0, :skip_instruct => true)
|
26
|
-
|
27
|
-
Bj.submit "./script/runner ./script/bj_invoker.rb",
|
28
|
-
:stdin => stdin
|
29
|
-
|
30
|
-
return nil # that means nothing!
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
@@ -1,42 +0,0 @@
|
|
1
|
-
#
|
2
|
-
# Base class for Workling Runners.
|
3
|
-
#
|
4
|
-
# Runners must subclass this and implement the method
|
5
|
-
#
|
6
|
-
# Workling::Remote::Runners::Base#run(clazz, method, options = {})
|
7
|
-
#
|
8
|
-
# which is responsible for pushing the requested job into the background. Depending
|
9
|
-
# on the Runner, this may require other code to dequeue the job. The actual
|
10
|
-
# invocation of the runner should be done like this:
|
11
|
-
#
|
12
|
-
# Workling.find(clazz, method).dispatch_to_worker_method(method, options)
|
13
|
-
#
|
14
|
-
# This ensures for consistent logging and handling of propagated exceptions. You can
|
15
|
-
# also call the convenience method
|
16
|
-
#
|
17
|
-
# Workling::Remote::Runners::Base#dispatch!(clazz, method, options)
|
18
|
-
#
|
19
|
-
# which invokes this for you.
|
20
|
-
#
|
21
|
-
module Workling
|
22
|
-
module Remote
|
23
|
-
module Runners
|
24
|
-
class Base
|
25
|
-
|
26
|
-
# runner uses this to connect to a job broker
|
27
|
-
cattr_accessor :client
|
28
|
-
|
29
|
-
# default logger defined in Workling::Base.logger
|
30
|
-
def logger
|
31
|
-
Workling::Base.logger
|
32
|
-
end
|
33
|
-
|
34
|
-
# find the worker instance and invoke it. Invoking the worker method like this ensures for
|
35
|
-
# consistent logging and handling of propagated exceptions.
|
36
|
-
def dispatch!(clazz, method, options)
|
37
|
-
Workling.find(clazz, method).dispatch_to_worker_method(method, options)
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
@@ -1,46 +0,0 @@
|
|
1
|
-
require 'workling/remote/runners/base'
|
2
|
-
require 'workling/routing/class_and_method_routing'
|
3
|
-
require 'workling/clients/memcache_queue_client'
|
4
|
-
|
5
|
-
#
|
6
|
-
# Runs Jobs over a Client. The client should be a subclass of Workling::Client::Base.
|
7
|
-
# Set the client like this:
|
8
|
-
#
|
9
|
-
# Workling::Remote::Runners::ClientRunner.client = Workling::Clients::AmqpClient.new
|
10
|
-
#
|
11
|
-
# Jobs are dispatched by requesting them on the Client. The Runner takes care of mapping of queue names to worker code.
|
12
|
-
# this is done with Workling::ClassAndMethodRouting, but you can use your own by sublassing Workling::Routing.
|
13
|
-
# Don’t worry about any of this if you’re not dealing directly with the queues.
|
14
|
-
#
|
15
|
-
# There’s a workling-client daemon that uses the configured invoker to retrieve work and dispatching these to the
|
16
|
-
# responsible workers. If you intend to run this on a remote machine, then just check out your rails project
|
17
|
-
# there and start up the workling client like this: ruby script/workling_client run.
|
18
|
-
#
|
19
|
-
module Workling
|
20
|
-
module Remote
|
21
|
-
module Runners
|
22
|
-
class ClientRunner < Workling::Remote::Runners::Base
|
23
|
-
|
24
|
-
# Routing class. Workling::Routing::ClassAndMethodRouting.new by default.
|
25
|
-
cattr_accessor :routing
|
26
|
-
@@routing ||= Workling::Routing::ClassAndMethodRouting.new
|
27
|
-
|
28
|
-
# The workling Client class. Workling::Clients::MemcacheQueueClient.new by default.
|
29
|
-
cattr_accessor :client
|
30
|
-
@@client ||= Workling::Clients::MemcacheQueueClient.new
|
31
|
-
|
32
|
-
# enqueues the job onto the client
|
33
|
-
def run(clazz, method, options = {})
|
34
|
-
|
35
|
-
# neet to connect in here as opposed to the constructor, since the EM loop is
|
36
|
-
# not available there.
|
37
|
-
@connected ||= self.class.client.connect
|
38
|
-
|
39
|
-
self.class.client.request(@@routing.queue_for(clazz, method), options)
|
40
|
-
|
41
|
-
return nil
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
@@ -1,23 +0,0 @@
|
|
1
|
-
require 'workling/remote/runners/base'
|
2
|
-
|
3
|
-
#
|
4
|
-
# directly dispatches to the worker method, in-process. options are first marshalled then dumped
|
5
|
-
# in order to simulate the sideeffects of a remote call.
|
6
|
-
#
|
7
|
-
module Workling
|
8
|
-
module Remote
|
9
|
-
module Runners
|
10
|
-
class NotRemoteRunner < Workling::Remote::Runners::Base
|
11
|
-
|
12
|
-
# directly dispatches to the worker method, in-process. options are first marshalled then dumped
|
13
|
-
# in order to simulate the sideeffects of a remote call.
|
14
|
-
def run(clazz, method, options = {})
|
15
|
-
options = Marshal.load(Marshal.dump(options)) # get this to behave more like the remote runners
|
16
|
-
dispatch!(clazz, method, options)
|
17
|
-
|
18
|
-
return nil # nada. niente.
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
@@ -1,17 +0,0 @@
|
|
1
|
-
require 'workling/remote/runners/base'
|
2
|
-
|
3
|
-
#
|
4
|
-
# this does absolutely nothing, mainly for testing
|
5
|
-
#
|
6
|
-
|
7
|
-
module Workling
|
8
|
-
module Remote
|
9
|
-
module Runners
|
10
|
-
class NotRunner < Workling::Remote::Runners::Base
|
11
|
-
def run(clazz, method, options = {})
|
12
|
-
return nil # nada. niente.
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
@@ -1,23 +0,0 @@
|
|
1
|
-
require 'workling/remote/runners/base'
|
2
|
-
|
3
|
-
module Workling
|
4
|
-
module Remote
|
5
|
-
module Runners
|
6
|
-
class RudeqRunner < Workling::Remote::Runners::Base
|
7
|
-
cattr_accessor :routing
|
8
|
-
cattr_accessor :client
|
9
|
-
|
10
|
-
def initialize
|
11
|
-
RudeqRunner.client = Workling::Rudeq::Client.new
|
12
|
-
RudeqRunner.routing = Workling::Routing::ClassAndMethodRouting.new
|
13
|
-
end
|
14
|
-
|
15
|
-
def run(clazz, method, options = {})
|
16
|
-
RudeqRunner.client.set(@@routing.queue_for(clazz, method), options)
|
17
|
-
|
18
|
-
return nil # empty.
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
@@ -1,38 +0,0 @@
|
|
1
|
-
require 'workling/remote/runners/base'
|
2
|
-
|
3
|
-
#
|
4
|
-
# Run the job over the spawn plugin. Refer to the README for instructions on
|
5
|
-
# installing Spawn.
|
6
|
-
#
|
7
|
-
# Spawn forks the entire process once for each job. This means that the job starts
|
8
|
-
# with a very low latency, but takes up more memory for each job.
|
9
|
-
#
|
10
|
-
# It's also possible to configure Spawn to start a Thread for each job. Do this
|
11
|
-
# by setting
|
12
|
-
#
|
13
|
-
# Workling::Remote::Runners::SpawnRunner.options = { :method => :thread }
|
14
|
-
#
|
15
|
-
# Have a look at the Spawn README to find out more about the characteristics of this.
|
16
|
-
#
|
17
|
-
module Workling
|
18
|
-
module Remote
|
19
|
-
module Runners
|
20
|
-
class SpawnRunner < Workling::Remote::Runners::Base
|
21
|
-
cattr_accessor :options
|
22
|
-
|
23
|
-
# use thread for development and test modes. easier to hunt down exceptions that way.
|
24
|
-
@@options = { :method => (RAILS_ENV == "test" || RAILS_ENV == "development" ? :fork : :thread) }
|
25
|
-
include Spawn if Workling.spawn_installed?
|
26
|
-
|
27
|
-
# dispatches to Spawn, using the :fork option.
|
28
|
-
def run(clazz, method, options = {})
|
29
|
-
spawn(SpawnRunner.options) do # exceptions are trapped in here.
|
30
|
-
dispatch!(clazz, method, options)
|
31
|
-
end
|
32
|
-
|
33
|
-
return nil # that means nothing!
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
@@ -1,24 +0,0 @@
|
|
1
|
-
require 'workling/return/store/base'
|
2
|
-
require 'workling/rudeq/client'
|
3
|
-
|
4
|
-
module Workling
|
5
|
-
module Return
|
6
|
-
module Store
|
7
|
-
class RudeqReturnStore < Base
|
8
|
-
cattr_accessor :client
|
9
|
-
|
10
|
-
def initialize
|
11
|
-
self.class.client = Workling::Rudeq::Client.new
|
12
|
-
end
|
13
|
-
|
14
|
-
def set(key, value)
|
15
|
-
self.class.client.set(key, value)
|
16
|
-
end
|
17
|
-
|
18
|
-
def get(key)
|
19
|
-
self.class.client.get(key)
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
data/lib/workling/rudeq.rb
DELETED
@@ -1,17 +0,0 @@
|
|
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
|
@@ -1,116 +0,0 @@
|
|
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
|