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.
Files changed (58) hide show
  1. data/bin/workling_client +9 -7
  2. data/{script → contrib}/bj_invoker.rb +0 -0
  3. data/{script → contrib}/starling_status.rb +0 -0
  4. data/lib/{cattr_accessor.rb → extensions/cattr_accessor.rb} +0 -0
  5. data/lib/{mattr_accessor.rb → extensions/mattr_accessor.rb} +0 -0
  6. data/lib/workling.rb +98 -94
  7. data/lib/workling/base.rb +6 -11
  8. data/lib/workling/clients/amqp_client.rb +13 -5
  9. data/lib/workling/clients/amqp_exchange_client.rb +19 -11
  10. data/lib/workling/clients/backgroundjob_client.rb +25 -0
  11. data/lib/workling/clients/base.rb +40 -8
  12. data/lib/workling/clients/broker_base.rb +63 -0
  13. data/lib/workling/clients/memcache_queue_client.rb +24 -12
  14. data/lib/workling/clients/memory_queue_client.rb +34 -0
  15. data/lib/workling/clients/not_client.rb +14 -0
  16. data/lib/workling/clients/not_remote_client.rb +17 -0
  17. data/lib/workling/clients/spawn_client.rb +47 -0
  18. data/lib/workling/clients/sqs_client.rb +9 -8
  19. data/lib/workling/clients/thread_client.rb +18 -0
  20. data/lib/workling/clients/xmpp_client.rb +14 -4
  21. data/lib/workling/discovery.rb +1 -1
  22. data/lib/workling/invokers/amqp_single_subscriber.rb +42 -0
  23. data/lib/workling/invokers/base.rb +124 -0
  24. data/lib/workling/invokers/basic_poller.rb +38 -0
  25. data/lib/workling/invokers/eventmachine_subscriber.rb +38 -0
  26. data/lib/workling/invokers/looped_subscriber.rb +34 -0
  27. data/lib/workling/invokers/thread_pool_poller.rb +165 -0
  28. data/lib/workling/invokers/threaded_poller.rb +149 -0
  29. data/lib/workling/remote.rb +10 -41
  30. data/lib/workling/return/store/base.rb +7 -7
  31. data/lib/workling/return/store/memory_return_store.rb +0 -2
  32. data/lib/workling/return/store/starling_return_store.rb +7 -8
  33. data/lib/workling/routing/base.rb +1 -4
  34. data/lib/workling/routing/class_and_method_routing.rb +0 -2
  35. data/lib/workling/routing/static_routing.rb +0 -4
  36. data/lib/{workling_server.rb → workling_daemon.rb} +27 -25
  37. metadata +21 -28
  38. data/lib/rude_q/client.rb +0 -11
  39. data/lib/workling/remote/invokers/amqp_single_subscriber.rb +0 -45
  40. data/lib/workling/remote/invokers/base.rb +0 -124
  41. data/lib/workling/remote/invokers/basic_poller.rb +0 -41
  42. data/lib/workling/remote/invokers/eventmachine_subscriber.rb +0 -41
  43. data/lib/workling/remote/invokers/looped_subscriber.rb +0 -38
  44. data/lib/workling/remote/invokers/thread_pool_poller.rb +0 -169
  45. data/lib/workling/remote/invokers/threaded_poller.rb +0 -153
  46. data/lib/workling/remote/runners/amqp_exchange_runner.rb +0 -45
  47. data/lib/workling/remote/runners/backgroundjob_runner.rb +0 -35
  48. data/lib/workling/remote/runners/base.rb +0 -42
  49. data/lib/workling/remote/runners/client_runner.rb +0 -46
  50. data/lib/workling/remote/runners/not_remote_runner.rb +0 -23
  51. data/lib/workling/remote/runners/not_runner.rb +0 -17
  52. data/lib/workling/remote/runners/rudeq_runner.rb +0 -23
  53. data/lib/workling/remote/runners/spawn_runner.rb +0 -38
  54. data/lib/workling/remote/runners/starling_runner.rb +0 -13
  55. data/lib/workling/return/store/rudeq_return_store.rb +0 -24
  56. data/lib/workling/rudeq.rb +0 -7
  57. data/lib/workling/rudeq/client.rb +0 -17
  58. data/lib/workling/rudeq/poller.rb +0 -116
@@ -1,5 +1,7 @@
1
1
  #
2
- # Clients are responsible for communicating with a job broker (ie connecting to starling or rabbitmq.)
2
+ # Clients are responsible for dispatching jobs either to a broker (starling, rabbitmq etc) or invoke them (spawn)
3
+ #
4
+ # Clients that involve a broker should subclass Workling::Clients::BrokerBase
3
5
  #
4
6
  # Clients are used to request jobs on a broker, get results for a job from a broker, and subscribe to results
5
7
  # from a specific type of job.
@@ -8,9 +10,39 @@ module Workling
8
10
  module Clients
9
11
  class Base
10
12
 
13
+ #
14
+ # Load the required libraries, for this client
15
+ #
16
+ def self.load
17
+
18
+ end
19
+
20
+
21
+ #
22
+ # See if the libraries required for this client are installed
23
+ #
24
+ def self.installed?
25
+ true
26
+ end
27
+
28
+
11
29
  # returns the Workling::Base.logger
12
30
  def logger; Workling::Base.logger; end
13
31
 
32
+
33
+ #
34
+ # Dispatch a job to the client. If this client uses a job broker, then
35
+ # this method should submit it, otherwise it should run the job
36
+ #
37
+ # clazz: Name of the worker class
38
+ # method: Name of the methods on the worker
39
+ # options: optional arguments for the job
40
+ #
41
+ def dispatch(clazz, method, options = {})
42
+ raise NotImplementedError.new("Implement dispatch(clazz, method, options) in your client. ")
43
+ end
44
+
45
+
14
46
  #
15
47
  # Requests a job on the broker.
16
48
  #
@@ -18,8 +50,8 @@ module Workling
18
50
  # arguments: the argument to the worker method
19
51
  #
20
52
  def request(work_type, arguments)
21
- raise NotImplementedError.new("Implement request(work_type, arguments) in your client. ")
22
- end
53
+ raise WorklingError.new("This client does not involve a broker.")
54
+ end
23
55
 
24
56
  #
25
57
  # Gets job results off a job broker. Returns nil if there are no results.
@@ -27,7 +59,7 @@ module Workling
27
59
  # worker_uid: the uid returned by workling when the work was dispatched
28
60
  #
29
61
  def retrieve(work_uid)
30
- raise NotImplementedError.new("Implement retrieve(work_uid) in your client. ")
62
+ raise WorklingError.new("This client does not involve a broker.")
31
63
  end
32
64
 
33
65
  #
@@ -36,22 +68,22 @@ module Workling
36
68
  # worker_type:
37
69
  #
38
70
  def subscribe(work_type)
39
- raise NotImplementedError.new("Implement subscribe(work_type) in your client. ")
71
+ raise WorklingError.new("This client does not involve a broker.")
40
72
  end
41
73
 
42
74
  #
43
75
  # Opens a connection to the job broker.
44
76
  #
45
77
  def connect
46
- raise NotImplementedError.new("Implement connect() in your client. ")
78
+ raise WorklingError.new("This client does not involve a broker.")
47
79
  end
48
80
 
49
81
  #
50
82
  # Closes the connection to the job broker.
51
83
  #
52
84
  def close
53
- raise NotImplementedError.new("Implement close() in your client. ")
85
+ raise WorklingError.new("This client does not involve a broker.")
54
86
  end
55
87
  end
56
88
  end
57
- end
89
+ end
@@ -0,0 +1,63 @@
1
+ module Workling
2
+ module Clients
3
+ class BrokerBase < Base
4
+
5
+ #
6
+ # Dispatch a job to the client. If this client uses a job broker, then
7
+ # this method should submit it, otherwise it should run the job
8
+ #
9
+ # clazz: Name of the worker class
10
+ # method: Name of the methods on the worker
11
+ # options: optional arguments for the job
12
+ #
13
+ def dispatch(clazz, method, options = {})
14
+ @connected ||= connect
15
+ request(Workling::Remote.routing.queue_for(clazz, method), options)
16
+ return nil
17
+ end
18
+
19
+
20
+ #
21
+ # Requests a job on the broker.
22
+ #
23
+ # work_type:
24
+ # arguments: the argument to the worker method
25
+ #
26
+ def request(work_type, arguments)
27
+ raise NotImplementedError.new("Implement request(work_type, arguments) in your client. ")
28
+ end
29
+
30
+ #
31
+ # Gets job results off a job broker. Returns nil if there are no results.
32
+ #
33
+ # worker_uid: the uid returned by workling when the work was dispatched
34
+ #
35
+ def retrieve(work_uid)
36
+ raise NotImplementedError.new("Implement retrieve(work_uid) in your client. ")
37
+ end
38
+
39
+ #
40
+ # Subscribe to job results in a job broker.
41
+ #
42
+ # worker_type:
43
+ #
44
+ def subscribe(work_type)
45
+ raise NotImplementedError.new("Implement subscribe(work_type) in your client. ")
46
+ end
47
+
48
+ #
49
+ # Opens a connection to the job broker.
50
+ #
51
+ def connect
52
+ raise NotImplementedError.new("Implement connect() in your client. ")
53
+ end
54
+
55
+ #
56
+ # Closes the connection to the job broker.
57
+ #
58
+ def close
59
+ raise NotImplementedError.new("Implement close() in your client. ")
60
+ end
61
+ end
62
+ end
63
+ end
@@ -1,6 +1,3 @@
1
- require 'workling/clients/base'
2
- require 'memcache'
3
-
4
1
  #
5
2
  # This client can be used for all Queue Servers that speak Memcached, such as Starling.
6
3
  #
@@ -12,12 +9,26 @@ require 'memcache'
12
9
  #
13
10
  module Workling
14
11
  module Clients
15
- class MemcacheQueueClient < Workling::Clients::Base
16
-
17
- # the class with which the connection is instantiated
18
- cattr_accessor :memcache_client_class
19
- @@memcache_client_class ||= ::MemCache
20
-
12
+ class MemcacheQueueClient < Workling::Clients::BrokerBase
13
+
14
+ def self.installed?
15
+ begin
16
+ require 'starling'
17
+ rescue LoadError
18
+ end
19
+
20
+ Object.const_defined? "Starling"
21
+ end
22
+
23
+ def self.load
24
+ begin
25
+ gem 'memcache-client'
26
+ require 'memcache'
27
+ rescue Gem::LoadError
28
+ Workling::Base.logger.info "WORKLING: couldn't find memcache-client. Install: \"gem install memcache-client\". "
29
+ end
30
+ end
31
+
21
32
  # the url with which the memcache client expects to reach starling
22
33
  attr_accessor :queueserver_urls
23
34
 
@@ -35,11 +46,11 @@ module Workling
35
46
  def connect
36
47
  @queueserver_urls = Workling.config[:listens_on].split(',').map { |url| url ? url.strip : url }
37
48
  options = [@queueserver_urls, Workling.config[:memcache_options]].compact
38
- self.connection = MemcacheQueueClient.memcache_client_class.new(*options)
39
-
49
+ self.connection = ::MemCache.new(*options)
50
+
40
51
  raise_unless_connected!
41
52
  end
42
-
53
+
43
54
  # closes the memcache connection
44
55
  def close
45
56
  self.connection.flush_all
@@ -86,6 +97,7 @@ module Workling
86
97
  raise Workling::WorklingConnectionError.new("#{e.class.to_s} - #{e.message}")
87
98
  end
88
99
  end
100
+
89
101
  end
90
102
  end
91
103
  end
@@ -0,0 +1,34 @@
1
+ module Workling
2
+ module Clients
3
+ class MemoryQueueClient < Workling::Clients::BrokerBase
4
+
5
+ def initialize
6
+ @subscribers ||= {}
7
+ @queues ||= {}
8
+ end
9
+
10
+ # collects the worker blocks in a hash
11
+ def subscribe(work_type, &block)
12
+ @subscribers[work_type] = block
13
+ end
14
+
15
+ # immediately invokes the required worker block
16
+ def request(work_type, arguments)
17
+ if subscription = @subscribers[work_type]
18
+ subscription.call(arguments)
19
+ else
20
+ @queues[work_type] ||= []
21
+ @queues[work_type] << arguments
22
+ end
23
+ end
24
+
25
+ def retrieve(work_type)
26
+ queue = @queues[work_type]
27
+ queue.pop if queue
28
+ end
29
+
30
+ def connect; true; end
31
+ def close; true; end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,14 @@
1
+ #
2
+ # Dont actually run the job...
3
+ #
4
+ module Workling
5
+ module Clients
6
+ class NotClient < Workling::Clients::Base
7
+
8
+ def dispatch(clazz, method, options = {})
9
+ return nil # nada. niente.
10
+ end
11
+
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,17 @@
1
+ #
2
+ # Run the job inline
3
+ #
4
+ module Workling
5
+ module Clients
6
+ class NotRemoteClient < Workling::Clients::Base
7
+
8
+ def dispatch(clazz, method, options = {})
9
+ options = Marshal.load(Marshal.dump(options)) # get this to behave more like the remote runners
10
+ Workling.find(clazz, method).dispatch_to_worker_method(method, options)
11
+
12
+ return nil # nada. niente.
13
+ end
14
+
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,47 @@
1
+ #
2
+ # Run the job over the spawn plugin. Refer to the README for instructions on
3
+ # installing Spawn.
4
+ #
5
+ # Spawn forks the entire process once for each job. This means that the job starts
6
+ # with a very low latency, but takes up more memory for each job.
7
+ #
8
+ # It's also possible to configure Spawn to start a Thread for each job. Do this
9
+ # by setting
10
+ #
11
+ # Workling::Clients::SpawnClient.options = { :method => :thread }
12
+ #
13
+ # Have a look at the Spawn README to find out more about the characteristics of this.
14
+ #
15
+ module Workling
16
+ module Clients
17
+ class SpawnClient < Workling::Clients::Base
18
+
19
+ def self.installed?
20
+ begin
21
+ require 'spawn'
22
+ rescue LoadError
23
+ end
24
+
25
+ Object.const_defined? "Spawn"
26
+ end
27
+
28
+ cattr_writer :options
29
+ def options
30
+ return @@options if defined?(@@options)
31
+ # use thread for development and test modes. easier to hunt down exceptions that way.
32
+ @@options = { :method => (RAILS_ENV == "test" || RAILS_ENV == "development" ? :fork : :thread) }
33
+ end
34
+
35
+ include Spawn if installed?
36
+
37
+ def dispatch(clazz, method, options = {})
38
+ spawn(SpawnRunner.options) do # exceptions are trapped in here.
39
+ Workling.find(clazz, method).dispatch_to_worker_method(method, options)
40
+ end
41
+
42
+ return nil # that means nothing!
43
+ end
44
+
45
+ end
46
+ end
47
+ end
@@ -1,4 +1,3 @@
1
- require 'workling/clients/base'
2
1
  require 'json'
3
2
  require 'right_aws'
4
3
 
@@ -27,15 +26,17 @@ require 'right_aws'
27
26
  #
28
27
  module Workling
29
28
  module Clients
30
- class SqsClient < Workling::Clients::Base
29
+ class SqsClient < Workling::Clients::BrokerBase
31
30
 
32
- AWS_MAX_QUEUE_NAME = 80
31
+ unless defined?(AWS_MAX_QUEUE_NAME)
32
+ AWS_MAX_QUEUE_NAME = 80
33
33
 
34
- # Note that 10 is the maximum number of messages that can be retrieved
35
- # in a single request.
36
- DEFAULT_MESSAGES_PER_REQ = 10
37
- DEFAULT_VISIBILITY_TIMEOUT = 30
38
- DEFAULT_VISIBILITY_RESERVE = 10
34
+ # Note that 10 is the maximum number of messages that can be retrieved
35
+ # in a single request.
36
+ DEFAULT_MESSAGES_PER_REQ = 10
37
+ DEFAULT_VISIBILITY_TIMEOUT = 30
38
+ DEFAULT_VISIBILITY_RESERVE = 10
39
+ end
39
40
 
40
41
  # Mainly exposed for testing purposes
41
42
  attr_reader :sqs_options
@@ -0,0 +1,18 @@
1
+ #
2
+ # Spawns a Thread. Used for Tests only, to simulate a remote runner more realistically.
3
+ #
4
+ module Workling
5
+ module Clients
6
+ class ThreadClient < Workling::Clients::Base
7
+
8
+ def dispatch(clazz, method, options = {})
9
+ Thread.new {
10
+ Workling.find(clazz, method).dispatch_to_worker_method(method, options)
11
+ }
12
+
13
+ return nil
14
+ end
15
+
16
+ end
17
+ end
18
+ end
@@ -1,6 +1,3 @@
1
- require 'workling/clients/base'
2
- Workling.try_load_xmpp4r
3
-
4
1
  #
5
2
  # An XMPP client
6
3
  #
@@ -43,7 +40,20 @@ Workling.try_load_xmpp4r
43
40
 
44
41
  module Workling
45
42
  module Clients
46
- class XmppClient < Workling::Clients::Base
43
+ class XmppClient < Workling::Clients::BrokerBase
44
+
45
+ def self.load
46
+ begin
47
+ gem "xmpp4r"
48
+ require 'xmpp4r'
49
+ require "xmpp4r/pubsub"
50
+ require "xmpp4r/pubsub/helper/servicehelper.rb"
51
+ require "xmpp4r/pubsub/helper/nodebrowser.rb"
52
+ require "xmpp4r/pubsub/helper/nodehelper.rb"
53
+ rescue Exception => e
54
+ raise WorklingError.new("Couldnt load the XMPP library. check that you have the xmpp4r gem installed")
55
+ end
56
+ end
47
57
 
48
58
  # starts the client.
49
59
  def connect
@@ -4,7 +4,7 @@
4
4
  module Workling
5
5
  class Discovery
6
6
  cattr_accessor :discovered
7
- @@discovered = []
7
+ @@discovered ||= []
8
8
 
9
9
  # requires worklings so that they are added to routing.
10
10
  def self.discover!
@@ -0,0 +1,42 @@
1
+ require 'eventmachine'
2
+
3
+ #
4
+ # TODO - Subscribes a single worker to a single queue
5
+ #
6
+ module Workling
7
+ module Invokers
8
+ class AmqpSingleSubscriber < Workling::Invokers::Base
9
+
10
+ def initialize(routing, client_class)
11
+ super
12
+ end
13
+
14
+ #
15
+ # Starts EM loop and sets up subscription callback for the worker
16
+ # Create the queue and bind to exchange using the routing key
17
+ #
18
+ def listen
19
+ EM.run do
20
+ connect do
21
+ queue_name = @routing.queue_for
22
+ routing_key = @routing.routing_key_for
23
+
24
+ # temp stuff to hook the queues and exchanges up
25
+ # wildcard routing - # (match all)
26
+ exch = MQ.topic
27
+ q = MQ.queue(queue_name)
28
+ q.bind(exch, :key => routing_key)
29
+
30
+ @client.subscribe(queue_name) do |args|
31
+ run(queue_name, args)
32
+ end
33
+ end
34
+ end
35
+ end
36
+
37
+ def stop
38
+ EM.stop if EM.reactor_running?
39
+ end
40
+ end
41
+ end
42
+ end