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.
Files changed (44) hide show
  1. data/lib/cattr_accessor.rb +51 -0
  2. data/lib/mattr_accessor.rb +55 -0
  3. data/lib/rude_q/client.rb +11 -0
  4. data/lib/workling/base.rb +115 -0
  5. data/lib/workling/clients/amqp_client.rb +38 -0
  6. data/lib/workling/clients/amqp_exchange_client.rb +50 -0
  7. data/lib/workling/clients/base.rb +57 -0
  8. data/lib/workling/clients/memcache_queue_client.rb +91 -0
  9. data/lib/workling/clients/sqs_client.rb +162 -0
  10. data/lib/workling/clients/xmpp_client.rb +100 -0
  11. data/lib/workling/discovery.rb +16 -0
  12. data/lib/workling/remote/invokers/amqp_single_subscriber.rb +45 -0
  13. data/lib/workling/remote/invokers/base.rb +124 -0
  14. data/lib/workling/remote/invokers/basic_poller.rb +41 -0
  15. data/lib/workling/remote/invokers/eventmachine_subscriber.rb +41 -0
  16. data/lib/workling/remote/invokers/looped_subscriber.rb +38 -0
  17. data/lib/workling/remote/invokers/thread_pool_poller.rb +169 -0
  18. data/lib/workling/remote/invokers/threaded_poller.rb +153 -0
  19. data/lib/workling/remote/runners/amqp_exchange_runner.rb +45 -0
  20. data/lib/workling/remote/runners/backgroundjob_runner.rb +35 -0
  21. data/lib/workling/remote/runners/base.rb +42 -0
  22. data/lib/workling/remote/runners/client_runner.rb +46 -0
  23. data/lib/workling/remote/runners/not_remote_runner.rb +23 -0
  24. data/lib/workling/remote/runners/not_runner.rb +17 -0
  25. data/lib/workling/remote/runners/rudeq_runner.rb +23 -0
  26. data/lib/workling/remote/runners/spawn_runner.rb +38 -0
  27. data/lib/workling/remote/runners/starling_runner.rb +13 -0
  28. data/lib/workling/remote.rb +69 -0
  29. data/lib/workling/return/store/base.rb +42 -0
  30. data/lib/workling/return/store/iterator.rb +24 -0
  31. data/lib/workling/return/store/memory_return_store.rb +26 -0
  32. data/lib/workling/return/store/rudeq_return_store.rb +24 -0
  33. data/lib/workling/return/store/starling_return_store.rb +31 -0
  34. data/lib/workling/routing/base.rb +16 -0
  35. data/lib/workling/routing/class_and_method_routing.rb +57 -0
  36. data/lib/workling/routing/static_routing.rb +47 -0
  37. data/lib/workling/rudeq/client.rb +17 -0
  38. data/lib/workling/rudeq/poller.rb +116 -0
  39. data/lib/workling/rudeq.rb +7 -0
  40. data/lib/workling.rb +195 -0
  41. data/lib/workling_server.rb +108 -0
  42. data/script/bj_invoker.rb +11 -0
  43. data/script/starling_status.rb +37 -0
  44. metadata +44 -1
@@ -0,0 +1,153 @@
1
+ require 'workling/remote/invokers/base'
2
+
3
+ #
4
+ # A threaded polling Invoker.
5
+ #
6
+ # TODO: refactor this to make use of the base class.
7
+ #
8
+ module Workling
9
+ module Remote
10
+ module Invokers
11
+ class ThreadedPoller < Workling::Remote::Invokers::Base
12
+
13
+ cattr_accessor :sleep_time, :reset_time
14
+
15
+ def initialize(routing, client_class)
16
+ super
17
+
18
+ ThreadedPoller.sleep_time = Workling.config[:sleep_time] || 2
19
+ ThreadedPoller.reset_time = Workling.config[:reset_time] || 30
20
+
21
+ @workers = ThreadGroup.new
22
+ @mutex = Mutex.new
23
+ end
24
+
25
+ def listen
26
+ # Create a thread for each worker.
27
+ Workling::Discovery.discovered.each do |clazz|
28
+ logger.debug("Discovered listener #{clazz}")
29
+ @workers.add(Thread.new(clazz) { |c| clazz_listen(c) })
30
+ end
31
+
32
+ # Wait for all workers to complete
33
+ @workers.list.each { |t| t.join }
34
+
35
+ logger.debug("Reaped listener threads. ")
36
+
37
+ # Clean up all the connections.
38
+ if defined?(ActiveRecord::Base)
39
+ ActiveRecord::Base.verify_active_connections!
40
+ end
41
+
42
+ logger.debug("Cleaned up connection: out!")
43
+ end
44
+
45
+ # Check if all Worker threads have been started.
46
+ def started?
47
+ logger.debug("checking if started... list size is #{ worker_threads }")
48
+ Workling::Discovery.discovered.size == worker_threads
49
+ end
50
+
51
+ # number of worker threads running
52
+ def worker_threads
53
+ @workers.list.size
54
+ end
55
+
56
+ # Gracefully stop processing
57
+ def stop
58
+ logger.info("stopping threaded poller...")
59
+ sleep 1 until started? # give it a chance to start up before shutting down.
60
+ logger.info("Giving Listener Threads a chance to shut down. This may take a while... ")
61
+ @workers.list.each { |w| w[:shutdown] = true }
62
+ logger.info("Listener threads were shut down. ")
63
+ end
64
+
65
+ # Listen for one worker class
66
+ def clazz_listen(clazz)
67
+ logger.debug("Listener thread #{clazz.name} started")
68
+
69
+ # Read thread configuration if available
70
+ if Workling.config.has_key?(:listeners)
71
+ if Workling.config[:listeners].has_key?(clazz.to_s)
72
+ config = Workling.config[:listeners][clazz.to_s].symbolize_keys
73
+ thread_sleep_time = config[:sleep_time] if config.has_key?(:sleep_time)
74
+ Thread.current.priority = config[:priority] if config.has_key?(:priority)
75
+ end
76
+ end
77
+
78
+ thread_sleep_time ||= self.class.sleep_time
79
+
80
+ # Setup connection to client (one per thread)
81
+ connection = @client_class.new
82
+ connection.connect
83
+ logger.info("** Starting client #{ connection.class } for #{clazz.name} queue")
84
+
85
+ # Start dispatching those messages
86
+ while (!Thread.current[:shutdown]) do
87
+ begin
88
+
89
+ # Thanks for this Brent!
90
+ #
91
+ # ...Just a heads up, due to how rails’ MySQL adapter handles this
92
+ # call ‘ActiveRecord::Base.connection.active?’, you’ll need
93
+ # to wrap the code that checks for a connection in in a mutex.
94
+ #
95
+ # ....I noticed this while working with a multi-core machine that
96
+ # was spawning multiple workling threads. Some of my workling
97
+ # threads would hit serious issues at this block of code without
98
+ # the mutex.
99
+ #
100
+ if defined?(ActiveRecord::Base)
101
+ @mutex.synchronize do
102
+ unless ActiveRecord::Base.connection.active? # Keep MySQL connection alive
103
+ unless ActiveRecord::Base.connection.reconnect!
104
+ logger.fatal("Failed - Database not available!")
105
+ break
106
+ end
107
+ end
108
+ end
109
+ end
110
+
111
+ # Dispatch and process the messages
112
+ n = dispatch!(connection, clazz)
113
+ logger.debug("Listener thread #{clazz.name} processed #{n.to_s} queue items") if n > 0
114
+ sleep(thread_sleep_time) unless n > 0
115
+
116
+ # If there is a memcache error, hang for a bit to give it a chance to fire up again
117
+ # and reset the connection.
118
+ rescue Workling::WorklingConnectionError
119
+ logger.warn("Listener thread #{clazz.name} failed to connect. Resetting connection.")
120
+ sleep(self.class.reset_time)
121
+ connection.reset
122
+ end
123
+ end
124
+
125
+ logger.debug("Listener thread #{clazz.name} ended")
126
+ end
127
+
128
+ # Dispatcher for one worker class. Will throw MemCacheError if unable to connect.
129
+ # Returns the number of worker methods called
130
+ def dispatch!(connection, clazz)
131
+ n = 0
132
+ for queue in @routing.queue_names_routing_class(clazz)
133
+ begin
134
+ result = connection.retrieve(queue)
135
+ if result
136
+ n += 1
137
+ handler = @routing[queue]
138
+ method_name = @routing.method_name(queue)
139
+ logger.debug("Calling #{handler.class.to_s}\##{method_name}(#{result.inspect})")
140
+ handler.dispatch_to_worker_method(method_name, result)
141
+ end
142
+ rescue Workling::WorklingError => e
143
+ logger.error("FAILED to connect with queue #{ queue }: #{ e } }")
144
+ raise e
145
+ end
146
+ end
147
+
148
+ return n
149
+ end
150
+ end
151
+ end
152
+ end
153
+ end
@@ -0,0 +1,45 @@
1
+ require 'workling/remote/runners/base'
2
+
3
+ #
4
+ # Runs Jobs over a Client. The client should be a subclass of Workling::Client::Base.
5
+ # Set the client like this:
6
+ #
7
+ # Workling::Remote::Runners::ClientRunner.client = Workling::Clients::AmqpClient.new
8
+ #
9
+ # Jobs are dispatched by requesting them on the Client. The Runner takes care of mapping of queue names to worker code.
10
+ # this is done with Workling::ClassAndMethodRouting, but you can use your own by sublassing Workling::Routing.
11
+ # Don’t worry about any of this if you’re not dealing directly with the queues.
12
+ #
13
+ # There’s a workling-client daemon that uses the configured invoker to retrieve work and dispatching these to the
14
+ # responsible workers. If you intend to run this on a remote machine, then just check out your rails project
15
+ # there and start up the workling client like this: ruby script/workling_client run.
16
+ #
17
+ module Workling
18
+ module Remote
19
+ module Runners
20
+ class AmqpExchangeRunner < Workling::Remote::Runners::Base
21
+
22
+ # Routing class. Workling::Routing::ClassAndMethodRouting.new by default.
23
+ cattr_accessor :routing
24
+ @@routing ||= Workling::Routing::ClassAndMethodRouting.new
25
+
26
+ # The workling Client class. Workling::Clients::MemcacheQueueClient.new by default.
27
+ cattr_accessor :client
28
+ @@client ||= Workling::Clients::AmqpExchangeClient.new
29
+
30
+ # enqueues the job onto the client
31
+ def run(clazz, method, options = {})
32
+
33
+ # neet to connect in here as opposed to the constructor, since the EM loop is
34
+ # not available there.
35
+ @connected ||= self.class.client.connect
36
+
37
+ # NOTE - currently hardcoded to use the default exchange
38
+ self.class.client.request("amq.topic", options)
39
+
40
+ return nil
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,35 @@
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
@@ -0,0 +1,42 @@
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
@@ -0,0 +1,46 @@
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
@@ -0,0 +1,23 @@
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
@@ -0,0 +1,17 @@
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
@@ -0,0 +1,23 @@
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
@@ -0,0 +1,38 @@
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
@@ -0,0 +1,13 @@
1
+ require 'workling/remote/runners/client_runner'
2
+
3
+ #
4
+ # DEPRECATED. Should use ClientRunner instead.
5
+ #
6
+ module Workling
7
+ module Remote
8
+ module Runners
9
+ class StarlingRunner < Workling::Remote::Runners::ClientRunner
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,69 @@
1
+ require "workling/remote/runners/not_remote_runner"
2
+ require "workling/remote/runners/spawn_runner"
3
+ require "workling/remote/runners/starling_runner"
4
+ require "workling/remote/runners/backgroundjob_runner"
5
+ require "workling/remote/invokers/threaded_poller"
6
+
7
+ require 'digest/md5'
8
+
9
+ #
10
+ # Scoping Module for Runners.
11
+ #
12
+ module Workling
13
+ module Remote
14
+
15
+ # Select which invoke to load based on what is defined in workling.yml. Defaults to thread_poller
16
+ # if none are specified.
17
+ def self.select_invoker
18
+ case(Workling.config[:invoker])
19
+ when 'basic_poller'
20
+ Workling::Remote::Invokers::BasicPoller
21
+
22
+ when 'thread_pool_poller'
23
+ Workling::Remote::Invokers::ThreadPoolPoller
24
+
25
+ when 'eventmachine_subscriber'
26
+ Workling::Remote::Invokers::EventmachineSubscriber
27
+
28
+ when 'threaded_poller', nil
29
+ Workling::Remote::Invokers::ThreadedPoller
30
+
31
+ else
32
+ Workling.logger.error("Nothing is known about #{Workling.config[:invoker]} defaulting to thread_poller")
33
+ Workling::Remote::Invokers::ThreadedPoller
34
+ end
35
+ end
36
+
37
+ # set the desired runner here. this is initialized with Workling.default_runner.
38
+ mattr_accessor :dispatcher
39
+
40
+ # set the desired invoker. this class grabs work from the job broker and executes it.
41
+ mattr_accessor :invoker
42
+ @@invoker ||= self.select_invoker
43
+
44
+ mattr_accessor :routing
45
+ @@routing ||= Workling::Routing::ClassAndMethodRouting
46
+
47
+ # retrieve the dispatcher or instantiate it using the defaults
48
+ def self.dispatcher
49
+ @@dispatcher ||= Workling.default_runner
50
+ end
51
+
52
+ # generates a unique identifier for this particular job.
53
+ def self.generate_uid(clazz, method)
54
+ uid = ::Digest::MD5.hexdigest("#{ clazz }:#{ method }:#{ rand(1 << 64) }:#{ Time.now }")
55
+ "#{ clazz.to_s.tableize }/#{ method }/#{ uid }".split("/").join(":")
56
+ end
57
+
58
+ # dispatches to a workling. writes the :uid for this work into the options hash, so make
59
+ # sure you pass in a hash if you want write to a return store in your workling.
60
+ def self.run(clazz, method, options = {})
61
+ uid = Workling::Remote.generate_uid(clazz, method)
62
+ options[:uid] = uid if options.kind_of?(Hash) && !options[:uid]
63
+ Workling.find(clazz, method) # this line raises a WorklingError if the method does not exist.
64
+ dispatcher.run(clazz, method, options)
65
+ uid
66
+ end
67
+
68
+ end
69
+ end
@@ -0,0 +1,42 @@
1
+ #
2
+ # Basic interface for getting and setting Data which needs to be passed between Workers and
3
+ # client code.
4
+ #
5
+ module Workling
6
+ module Return
7
+ module Store
8
+ mattr_accessor :instance
9
+
10
+ # set a value in the store with the given key. delegates to the returnstore.
11
+ def self.set(key, value)
12
+ self.instance.set(key, value)
13
+ end
14
+
15
+ # get a value from the store. this should be destructive. delegates to the returnstore.
16
+ def self.get(key)
17
+ self.instance.get(key)
18
+ end
19
+
20
+ #
21
+ # Base Class for Return Stores. Subclasses need to implement set and get.
22
+ #
23
+ class Base
24
+
25
+ # set a value in the store with the given key.
26
+ def set(key, value)
27
+ raise NotImplementedError.new("set(key, value) not implemented in #{ self.class }")
28
+ end
29
+
30
+ # get a value from the store. this should be destructive.
31
+ def get(key)
32
+ raise NotImplementedError.new("get(key) not implemented in #{ self.class }")
33
+ end
34
+
35
+ def iterator(key)
36
+ Workling::Return::Store::Iterator.new(key)
37
+ end
38
+
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,24 @@
1
+ #
2
+ # Iterator class for iterating over return values.
3
+ #
4
+ module Workling
5
+ module Return
6
+ module Store
7
+ class Iterator
8
+
9
+ include Enumerable
10
+
11
+ def initialize(uid)
12
+ @uid = uid
13
+ end
14
+
15
+ def each
16
+ while item = Workling.return.get(@uid)
17
+ yield item
18
+ end
19
+ end
20
+
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,26 @@
1
+ require 'workling/return/store/base'
2
+
3
+ #
4
+ # Stores directly into memory. This is for tests only - not for production use. aight?
5
+ #
6
+ module Workling
7
+ module Return
8
+ module Store
9
+ class MemoryReturnStore < Base
10
+ attr_accessor :sky
11
+
12
+ def initialize
13
+ self.sky = Hash.new([])
14
+ end
15
+
16
+ def set(key, value)
17
+ self.sky[key] << value
18
+ end
19
+
20
+ def get(key)
21
+ self.sky[key].shift
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,24 @@
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
@@ -0,0 +1,31 @@
1
+ require 'workling/return/store/base'
2
+ require 'workling/clients/memcache_queue_client'
3
+
4
+ #
5
+ # Recommended Return Store if you are using the Starling Runner. This
6
+ # Simply sets and gets values against queues. 'key' is the name of the respective Queue.
7
+ #
8
+ module Workling
9
+ module Return
10
+ module Store
11
+ class StarlingReturnStore < Base
12
+ cattr_accessor :client
13
+
14
+ def initialize
15
+ self.client = Workling::Clients::MemcacheQueueClient.new
16
+ self.client.connect
17
+ end
18
+
19
+ # set a value in the queue 'key'.
20
+ def set(key, value)
21
+ self.class.client.set(key, value)
22
+ end
23
+
24
+ # get a value from starling queue 'key'.
25
+ def get(key)
26
+ self.class.client.get(key)
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,16 @@
1
+ #
2
+ # Base Class for Routing. Routing takes the worker method TestWorker#something,
3
+ # and serializes the signature in some way.
4
+ #
5
+ module Workling
6
+ module Routing
7
+ class Base < Hash
8
+ # @@logger ||= ::RAILS_DEFAULT_LOGGER
9
+ # cattr_accessor :logger
10
+
11
+ def method_name
12
+ raise Exception.new("method_name not implemented.")
13
+ end
14
+ end
15
+ end
16
+ end