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.
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,51 @@
1
+ # Extends the class object with class and instance accessors for class attributes,
2
+ # just like the native attr* accessors for instance attributes.
3
+ #
4
+ # class Person
5
+ # cattr_accessor :hair_colors
6
+ # end
7
+ #
8
+ # Person.hair_colors = [:brown, :black, :blonde, :red]
9
+ class Class
10
+ def cattr_reader(*syms)
11
+ syms.flatten.each do |sym|
12
+ next if sym.is_a?(Hash)
13
+ class_eval(<<-EOS, __FILE__, __LINE__)
14
+ unless defined? @@#{sym} # unless defined? @@hair_colors
15
+ @@#{sym} = nil # @@hair_colors = nil
16
+ end # end
17
+ #
18
+ def self.#{sym} # def self.hair_colors
19
+ @@#{sym} # @@hair_colors
20
+ end # end
21
+ #
22
+ def #{sym} # def hair_colors
23
+ @@#{sym} # @@hair_colors
24
+ end # end
25
+ EOS
26
+ end
27
+ end
28
+
29
+ def cattr_writer(*syms)
30
+ syms.flatten.each do |sym|
31
+ class_eval(<<-EOS, __FILE__, __LINE__)
32
+ unless defined? @@#{sym} # unless defined? @@hair_colors
33
+ @@#{sym} = nil # @@hair_colors = nil
34
+ end # end
35
+ #
36
+ def self.#{sym}=(obj) # def self.hair_colors=(obj)
37
+ @@#{sym} = obj # @@hair_colors = obj
38
+ end # end
39
+ #
40
+ def #{sym}=(obj) # def hair_colors=(obj)
41
+ @@#{sym} = obj # @@hair_colors = obj
42
+ end # end
43
+ EOS
44
+ end
45
+ end
46
+
47
+ def cattr_accessor(*syms)
48
+ cattr_reader(*syms)
49
+ cattr_writer(*syms)
50
+ end
51
+ end
@@ -0,0 +1,55 @@
1
+ # Extends the module object with module and instance accessors for class attributes,
2
+ # just like the native attr* accessors for instance attributes.
3
+ #
4
+ # module AppConfiguration
5
+ # mattr_accessor :google_api_key
6
+ # self.google_api_key = "123456789"
7
+ #
8
+ # mattr_accessor :paypal_url
9
+ # self.paypal_url = "www.sandbox.paypal.com"
10
+ # end
11
+ #
12
+ # AppConfiguration.google_api_key = "overriding the api key!"
13
+ class Module
14
+ def mattr_reader(*syms)
15
+ syms.each do |sym|
16
+ next if sym.is_a?(Hash)
17
+ class_eval(<<-EOS, __FILE__, __LINE__)
18
+ unless defined? @@#{sym} # unless defined? @@pagination_options
19
+ @@#{sym} = nil # @@pagination_options = nil
20
+ end # end
21
+ #
22
+ def self.#{sym} # def self.pagination_options
23
+ @@#{sym} # @@pagination_options
24
+ end # end
25
+ #
26
+ def #{sym} # def pagination_options
27
+ @@#{sym} # @@pagination_options
28
+ end # end
29
+ EOS
30
+ end
31
+ end
32
+
33
+ def mattr_writer(*syms)
34
+ syms.each do |sym|
35
+ class_eval(<<-EOS, __FILE__, __LINE__)
36
+ unless defined? @@#{sym} # unless defined? @@pagination_options
37
+ @@#{sym} = nil # @@pagination_options = nil
38
+ end # end
39
+ #
40
+ def self.#{sym}=(obj) # def self.pagination_options=(obj)
41
+ @@#{sym} = obj # @@pagination_options = obj
42
+ end # end
43
+ #
44
+ def #{sym}=(obj) # def pagination_options=(obj)
45
+ @@#{sym} = obj # @@pagination_options = obj
46
+ end # end
47
+ EOS
48
+ end
49
+ end
50
+
51
+ def mattr_accessor(*syms)
52
+ mattr_reader(*syms)
53
+ mattr_writer(*syms)
54
+ end
55
+ end
@@ -0,0 +1,11 @@
1
+ #
2
+ # A RudeQ client that behvaes somewhat like memcache-client
3
+ #
4
+ module RudeQ
5
+ class Client
6
+ def initialize(*args); super(); end
7
+ def set(key, value); RudeQueue.set(key, value); end;
8
+ def get(key); RudeQueue.get(key); end;
9
+ def stats; ActiveRecord::Base.connection; end
10
+ end
11
+ end
@@ -0,0 +1,115 @@
1
+ #require 'struct'
2
+
3
+ #
4
+ # All worker classes must inherit from this class, and be saved in app/workers.
5
+ #
6
+ # The Worker lifecycle:
7
+ # The Worker is loaded once, at which point the instance method 'create' is called.
8
+ #
9
+ # Invoking Workers:
10
+ # Calling async_my_method on the worker class will trigger background work.
11
+ # This means that the loaded Worker instance will receive a call to the method
12
+ # my_method(:uid => "thisjobsuid2348732947923").
13
+ #
14
+ # The Worker method must have a single hash argument. Note that the job :uid will
15
+ # be merged into the hash.
16
+ #
17
+ module Workling
18
+ class Base
19
+ cattr_writer :logger
20
+ def self.logger
21
+ @@logger ||= ::RAILS_DEFAULT_LOGGER
22
+ end
23
+
24
+ cattr_accessor :exposed_methods
25
+ @@exposed_methods ||= {}
26
+
27
+ def self.inherited(subclass)
28
+ Workling::Discovery.discovered << subclass
29
+ end
30
+
31
+ # expose a method using a custom queue name
32
+ def self.expose(method, options)
33
+ self.exposed_methods[method.to_s] = options[:as]
34
+ end
35
+
36
+ # identify the queue for a given method
37
+ def self.queue_for(method)
38
+ if self.exposed_methods.has_key?(method)
39
+ self.exposed_methods[method]
40
+ else
41
+ "#{ self.to_s.tableize }/#{ method }".split("/").join("__") # Don't split with : because it messes up memcache stats
42
+ end
43
+ end
44
+
45
+ # identify the method linked to the queue
46
+ def self.method_for(queue)
47
+ if self.exposed_methods.invert.has_key?(queue)
48
+ self.exposed_methods.invert[queue]
49
+ else
50
+ queue.split("__").last
51
+ end
52
+ end
53
+
54
+ def method_for(queue)
55
+ self.class.method_for(queue)
56
+ end
57
+
58
+
59
+ def initialize
60
+ super
61
+
62
+ create
63
+ end
64
+
65
+ # Put worker initialization code in here. This is good for restarting jobs that
66
+ # were interrupted.
67
+ def create
68
+ end
69
+
70
+ # override this if you want to set up exception notification
71
+ def notify_exception(exception, method, options)
72
+ logger.error "WORKLING ERROR: runner could not invoke #{ self.class }:#{ method } with #{ options.inspect }. error was: #{ exception.inspect }\n #{ exception.backtrace.join("\n") }"
73
+ end
74
+
75
+ # takes care of suppressing remote errors but raising Workling::WorklingNotFoundError
76
+ # where appropriate. swallow workling exceptions so that everything behaves like remote code.
77
+ # otherwise StarlingRunner and SpawnRunner would behave too differently to NotRemoteRunner.
78
+ def dispatch_to_worker_method(method, options = {})
79
+ begin
80
+ options = default_options.merge(options)
81
+ self.send(method, options)
82
+ rescue Workling::WorklingError => e
83
+ raise e
84
+ rescue Exception => e
85
+ notify_exception e, method, options
86
+ on_error(e) if respond_to?(:on_error)
87
+
88
+ # reraise after logging. the exception really can't go anywhere in many cases. (spawn traps the exception)
89
+ raise e if Workling.raise_exceptions?
90
+ end
91
+ end
92
+
93
+ # supply default_options as a hash in classes that inherit Workling::Base
94
+ def default_options
95
+ {}
96
+ end
97
+
98
+ # thanks to blaine cook for this suggestion.
99
+ def self.method_missing(method, *args, &block)
100
+ if method.to_s =~ /^asynch?_(.*)/
101
+ Workling::Remote.run(self.to_s.dasherize, $1, *args)
102
+ else
103
+ super
104
+ end
105
+ end
106
+
107
+ def self.logger
108
+ @logger ||= defined?(RAILS_DEFAULT_LOGGER) ? ::RAILS_DEFAULT_LOGGER : Logger.new($stdout)
109
+ end
110
+
111
+ def logger
112
+ self.class.logger
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,38 @@
1
+ require 'workling/clients/base'
2
+ Workling.try_load_an_amqp_client
3
+
4
+ #
5
+ # An Ampq client
6
+ #
7
+ module Workling
8
+ module Clients
9
+ class AmqpClient < Workling::Clients::Base
10
+
11
+ # starts the client.
12
+ def connect
13
+ begin
14
+ connection = AMQP.start((Workling.config[:amqp_options] ||{}).symbolize_keys)
15
+ @amq = MQ.new connection
16
+ rescue
17
+ raise WorklingError.new("couldn't start amq client. if you're running this in a server environment, then make sure the server is evented (ie use thin or evented mongrel, not normal mongrel.)")
18
+ end
19
+ end
20
+
21
+ # no need for explicit closing. when the event loop
22
+ # terminates, the connection is closed anyway.
23
+ def close; true; end
24
+
25
+ # subscribe to a queue
26
+ def subscribe(key)
27
+ @amq.queue(key).subscribe do |value|
28
+ data = Marshal.load(value) rescue value
29
+ yield data
30
+ end
31
+ end
32
+
33
+ # request and retrieve work
34
+ def retrieve(key); @amq.queue(key); end
35
+ def request(key, value); @amq.queue(key).publish(Marshal.dump(value)); end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,50 @@
1
+ require 'workling/clients/base'
2
+ Workling.try_load_an_amqp_client
3
+
4
+ #
5
+ # An Ampq client
6
+ #
7
+ module Workling
8
+ module Clients
9
+ class AmqpExchangeClient < Workling::Clients::Base
10
+
11
+ # starts the client.
12
+ def connect
13
+ begin
14
+ @amq = MQ.new
15
+ rescue
16
+ raise WorklingError.new("couldn't start amq client. if you're running this in a server environment, then make sure the server is evented (ie use thin or evented mongrel, not normal mongrel.)")
17
+ end
18
+ end
19
+
20
+ # no need for explicit closing. when the event loop
21
+ # terminates, the connection is closed anyway.
22
+ def close; true; end
23
+
24
+ # subscribe to a queue
25
+ def subscribe(key)
26
+ @amq.queue(key).subscribe do |header, body|
27
+
28
+ puts "***** received msg with header - #{header.inspect}"
29
+
30
+ value = YAML.load(body)
31
+ yield value
32
+ end
33
+ end
34
+
35
+ # request and retrieve work
36
+ def retrieve(key)
37
+ @amq.queue(key)
38
+ end
39
+
40
+ # publish message to exchange
41
+ # using the specified routing key
42
+ def request(exchange_name, value)
43
+ key = value.delete(:routing_key)
44
+ msg = YAML.dump(value)
45
+ exchange = @amq.topic(exchange_name)
46
+ exchange.publish(msg, :routing_key => key)
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,57 @@
1
+ #
2
+ # Clients are responsible for communicating with a job broker (ie connecting to starling or rabbitmq.)
3
+ #
4
+ # Clients are used to request jobs on a broker, get results for a job from a broker, and subscribe to results
5
+ # from a specific type of job.
6
+ #
7
+ module Workling
8
+ module Clients
9
+ class Base
10
+
11
+ # returns the Workling::Base.logger
12
+ def logger; Workling::Base.logger; end
13
+
14
+ #
15
+ # Requests a job on the broker.
16
+ #
17
+ # work_type:
18
+ # arguments: the argument to the worker method
19
+ #
20
+ def request(work_type, arguments)
21
+ raise NotImplementedError.new("Implement request(work_type, arguments) in your client. ")
22
+ end
23
+
24
+ #
25
+ # Gets job results off a job broker. Returns nil if there are no results.
26
+ #
27
+ # worker_uid: the uid returned by workling when the work was dispatched
28
+ #
29
+ def retrieve(work_uid)
30
+ raise NotImplementedError.new("Implement retrieve(work_uid) in your client. ")
31
+ end
32
+
33
+ #
34
+ # Subscribe to job results in a job broker.
35
+ #
36
+ # worker_type:
37
+ #
38
+ def subscribe(work_type)
39
+ raise NotImplementedError.new("Implement subscribe(work_type) in your client. ")
40
+ end
41
+
42
+ #
43
+ # Opens a connection to the job broker.
44
+ #
45
+ def connect
46
+ raise NotImplementedError.new("Implement connect() in your client. ")
47
+ end
48
+
49
+ #
50
+ # Closes the connection to the job broker.
51
+ #
52
+ def close
53
+ raise NotImplementedError.new("Implement close() in your client. ")
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,91 @@
1
+ require 'workling/clients/base'
2
+ require 'memcache'
3
+
4
+ #
5
+ # This client can be used for all Queue Servers that speak Memcached, such as Starling.
6
+ #
7
+ # Wrapper for the memcache connection. The connection is made using fiveruns-memcache-client,
8
+ # or memcache-client, if this is not available. See the README for a discussion of the memcache
9
+ # clients.
10
+ #
11
+ # method_missing delegates all messages through to the underlying memcache connection.
12
+ #
13
+ module Workling
14
+ 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
+
21
+ # the url with which the memcache client expects to reach starling
22
+ attr_accessor :queueserver_urls
23
+
24
+ # the memcache connection object
25
+ attr_accessor :connection
26
+
27
+ #
28
+ # the client attempts to connect to queueserver using the configuration options found in
29
+ #
30
+ # Workling.config. this can be configured in config/workling.yml.
31
+ #
32
+ # the initialization code will raise an exception if memcache-client cannot connect
33
+ # to queueserver.
34
+ #
35
+ def connect
36
+ @queueserver_urls = Workling.config[:listens_on].split(',').map { |url| url ? url.strip : url }
37
+ options = [@queueserver_urls, Workling.config[:memcache_options]].compact
38
+ self.connection = MemcacheQueueClient.memcache_client_class.new(*options)
39
+
40
+ raise_unless_connected!
41
+ end
42
+
43
+ # closes the memcache connection
44
+ def close
45
+ self.connection.flush_all
46
+ self.connection.reset
47
+ end
48
+
49
+ # implements the client job request and retrieval
50
+ def request(key, value)
51
+ set(key, value)
52
+ end
53
+
54
+ def retrieve(key)
55
+ begin
56
+ get(key)
57
+ rescue MemCache::MemCacheError => e
58
+ # failed to enqueue, raise a workling error so that it propagates upwards
59
+ raise Workling::WorklingConnectionError.new("#{e.class.to_s} - #{e.message}")
60
+ end
61
+ end
62
+
63
+ private
64
+ # make sure we can actually connect to queueserver on the given port
65
+ def raise_unless_connected!
66
+ begin
67
+ self.connection.stats
68
+ rescue
69
+ raise Workling::QueueserverNotFoundError.new
70
+ end
71
+ end
72
+
73
+ [:get, :set].each do |method|
74
+ class_eval <<-EOS
75
+ def #{method}(*args, &block)
76
+ self.connection.#{method}(*args, &block)
77
+ end
78
+ EOS
79
+ end
80
+
81
+ # delegates directly through to the memcache connection.
82
+ def method_missing(method, *args)
83
+ begin
84
+ self.connection.send(method, *args)
85
+ rescue MemCache::MemCacheError => e
86
+ raise Workling::WorklingConnectionError.new("#{e.class.to_s} - #{e.message}")
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,162 @@
1
+ require 'workling/clients/base'
2
+ require 'json'
3
+ require 'right_aws'
4
+
5
+ #
6
+ # An SQS client
7
+ #
8
+ # Requires the following configuration in workling.yml:
9
+ #
10
+ # production:
11
+ # sqs_options:
12
+ # aws_access_key_id: <your AWS access key id>
13
+ # aws_secret_access_key: <your AWS secret access key>
14
+ #
15
+ # You can also add the following optional parameters:
16
+ #
17
+ # # Queue names consist of an optional prefix, followed by the environment
18
+ # # and the name of the key.
19
+ # prefix: foo_
20
+ #
21
+ # # The number of SQS messages to retrieve at once. The maximum and default
22
+ # # value is 10.
23
+ # messages_per_req: 5
24
+ #
25
+ # # The SQS visibility timeout for retrieved messages. Defaults to 30 seconds.
26
+ # visibility_timeout: 15
27
+ #
28
+ module Workling
29
+ module Clients
30
+ class SqsClient < Workling::Clients::Base
31
+
32
+ AWS_MAX_QUEUE_NAME = 80
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
39
+
40
+ # Mainly exposed for testing purposes
41
+ attr_reader :sqs_options
42
+ attr_reader :messages_per_req
43
+ attr_reader :visibility_timeout
44
+
45
+ # Starts the client.
46
+ def connect
47
+ @sqs_options = Workling.config[:sqs_options]
48
+
49
+ # Make sure that required options were specified
50
+ unless (@sqs_options.include?('aws_access_key_id') &&
51
+ @sqs_options.include?('aws_secret_access_key'))
52
+ raise WorklingError, 'Unable to start SqsClient due to missing SQS options'
53
+ end
54
+
55
+ # Optional settings
56
+ @messages_per_req = @sqs_options['messages_per_req'] || DEFAULT_MESSAGES_PER_REQ
57
+ @visibility_timeout = @sqs_options['visibility_timeout'] || DEFAULT_VISIBILITY_TIMEOUT
58
+ @visibility_reserve = @sqs_options['visibility_reserve'] || DEFAULT_VISIBILITY_RESERVE
59
+
60
+ begin
61
+ @sqs = RightAws::SqsGen2.new(
62
+ @sqs_options['aws_access_key_id'],
63
+ @sqs_options['aws_secret_access_key'],
64
+ :multi_thread => true)
65
+ rescue => e
66
+ raise WorklingError, "Unable to connect to SQS. Error: #{e}"
67
+ end
68
+ end
69
+
70
+ # No need for explicit closing, since there is no persistent
71
+ # connection to SQS.
72
+ def close
73
+ true
74
+ end
75
+
76
+ # Retrieve work.
77
+ def retrieve(key)
78
+ begin
79
+ # We're using a buffer per key to retrieve several messages at once,
80
+ # then return them one at a time until the buffer is empty.
81
+ # Workling seems to create one thread per worker class, each with its own
82
+ # client. But to be sure (and to be less dependent on workling internals),
83
+ # we store each buffer in a thread local variable.
84
+ buffer = Thread.current["buffer_#{key}"]
85
+ if buffer.nil? || buffer.empty?
86
+ Thread.current["buffer_#{key}"] = buffer = queue_for_key(key).receive_messages(
87
+ @messages_per_req, @visibility_timeout)
88
+ end
89
+
90
+ if buffer.empty?
91
+ nil
92
+ else
93
+ msg = buffer.shift
94
+
95
+ # We need to protect against the case that processing one of the
96
+ # messages in the buffer took so much time that the visibility
97
+ # timeout for the remaining messages has expired. To be on the
98
+ # safe side (since we need to leave enough time to delete the
99
+ # message), we drop it if more than half of the visibility timeout
100
+ # has elapsed.
101
+ if msg.received_at < (Time.now - (@visibility_timeout - @visibility_reserve))
102
+ nil
103
+ else
104
+ # Need to wrap in HashWithIndifferentAccess, as JSON serialization
105
+ # loses symbol keys.
106
+ parsed_msg = HashWithIndifferentAccess.new(JSON.parse(msg.body))
107
+
108
+ # Delete the msg from SQS, so we don't re-retrieve it after the
109
+ # visibility timeout. Ideally we would defer deleting a msg until
110
+ # after Workling has successfully processed it, but it currently
111
+ # doesn't provide the necessary hooks for this.
112
+ msg.delete
113
+
114
+ parsed_msg
115
+ end
116
+ end
117
+
118
+ rescue => e
119
+ logger.error "Error retrieving msg for key: #{key}; Error: #{e}\n#{e.backtrace.join("\n")}"
120
+ end
121
+
122
+ end
123
+
124
+ # Request work.
125
+ def request(key, value)
126
+ begin
127
+ queue_for_key(key).send_message(value.to_json)
128
+ rescue => e
129
+ logger.error "SQS Client: Error sending msg for key: #{key}, value: #{value.inspect}; Error: #{e}"
130
+ raise WorklingError, "Error sending msg for key: #{key}, value: #{value.inspect}; Error: #{e}"
131
+ end
132
+ end
133
+
134
+ # Returns the queue that corresponds to the specified key. Creates the
135
+ # queue if it doesn't exist yet.
136
+ def queue_for_key(key)
137
+ # Use thread local for storing queues, for the same reason as for buffers
138
+ Thread.current["queue_#{key}"] ||= @sqs.queue(queue_name(key), true, @visibility_timeout)
139
+ end
140
+
141
+ # Returns the queue name for the specified key. The name consists of an
142
+ # optional prefix, followed by the environment and the key itself. Note
143
+ # that with a long worker class / method name, the name could exceed the
144
+ # 80 character maximum for SQS queue names. We truncate the name until it
145
+ # fits, but there's still the danger of this not being unique any more.
146
+ # Might need to implement a more robust naming scheme...
147
+ def queue_name(key)
148
+ "#{@sqs_options['prefix'] || ''}#{env}_#{key}"[0, AWS_MAX_QUEUE_NAME]
149
+ end
150
+
151
+ private
152
+
153
+ def logger
154
+ Rails.logger
155
+ end
156
+
157
+ def env
158
+ Rails.env
159
+ end
160
+ end
161
+ end
162
+ end