sqewer 5.0.0 → 5.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3fe9d14faeab2b77f5551ae617cf50b24b803698
4
- data.tar.gz: 10973f30ea8433ebc3f0cdc2a4b8ae8705a24476
3
+ metadata.gz: ddea2036ab00b9c68e83ed4bcd64bf7a46ab5114
4
+ data.tar.gz: 9a0efcf0a664e35d628d1c602f7fb0339490233a
5
5
  SHA512:
6
- metadata.gz: bc139a5322ae65835d5ebdd0d95568e36f5d54a029340a6b834cd8528b64168c58d80e9b62790707b7eb69bdd9616cb20e781119f4d0e6cc713c82c226749bfe
7
- data.tar.gz: 52139badc74df3a2b208415063c5f336b98c294b630abbf95d20165882a01a6908d69139d73ba5e73ecbc52d0b595d1c73de8ded5b2b6ea433f0da87d0ea78d9
6
+ metadata.gz: 432aa4dca6829cf25a5a402b0d8da73cfc3719aba51479068fb7572bbac0badf15319970f97c015b95dcf3bcce25b1004233a0ecbf5e969ef238c4ce4db2a775
7
+ data.tar.gz: 2bce53adecc4d6e869b05c0a9d0cdafae7a4cf021b1e73f7ad25cbf061ac7ddd1fb61a2f571bc2a1c61415be35ea6900ae915a2ed8d577df26bb2c29208de0b1
data/.travis.yml CHANGED
@@ -8,3 +8,4 @@ env:
8
8
  - secure: E+uNoJmvjq5+3/PYUs2a1bRh7bCjAbcYEIKJzOVgIiI+gWB4dLpTKwVW/fqJbjCDIGPw9OwiwphN51zLEo0ie5AJIkavcjWRcdazKq8usokAz/A5Ilru5YvGXJ5UQtF8TJNsZfJGOGMJwL5d/MsDSd3/sjy88wrFiSeeNlHA06KDBrGdZXE4/dOb5Z84cSxPaD7nDaGP36V3Uv88X272oezODm9Mp+Fsf4goGoU9I9PBDD36pCXAlpURWpyWMKa2TzEXfgN43TYxta4p+bu6BA871df31j3BfVKwY1K/59eN9HqW8xWF9rgcgLo3NgQuaoqde3ryCE4jqKymjtG1/R5bdbQsn07R7/OagQMPVkbn07Aq+X6Q8GVTkrMl829z87QiMETNnzpsHl/1RD3DVnUo4k+XmqLbwW6NRl452j3eEHsiMvxf1vt8Qn1hu61qm98WGVNCGFWX/eAu/iTpvDcQOkoUuUEfGnXPaGeM8GT7tNdKptT8gsg/H0Dwb4d0qwA8uAEWttmZBmI9145hpnIk+hkDkH22dzhTus8d7CfFDSpu7s3y9434wiCYF5pkugyWJb5dd24d00ssgF5gqhLU/s48WcBwipl8mMGu/H/5ezh/pG9dL2uDIUjKRrUybE/vmDJGy8ZEDnOwJ04NJ701vQjFybgZRXXyU5ESEJQ=
9
9
  - secure: hq1T5MsHGmEnfQjOJlu/GzUPJ4WH0+lZOHezb4i0rFmRtWnmOMO+YUA34q9P6VQROk5KcAiRKtqZYmxZwTjyJVk2DTcJkvUAVzWBHD+MZAsH/lql+lnUJTuZRapYI85LChmEZkDMhYxZYfxTqGTbE4GjLtVtGN8zmTRStLxtvqyfiaU0SuGzyw9wfso/QhqHadQAQ7NttTYyiSiO2vHxK7rhmNi99MxAeVL3qZ3H2mcypSEE7CZd+nFa2CQxh/Guce0i+N2PDYTB6dsvA4xA5Xh/e+han3g4x/sRpic2C/9HS2zRYf0iN20+pFyotp5SaW3o5Q5S3iUqQtyZoR2lN1YMd4csyyKp/0G4QOjAPIN3FIef/RTVLqdfZXaord4iAg9GN9eKdtgYuS7JgyDl0VOmTpS2RYuDP+PGR2HRXXVc0gHt2aFl/oy+DTXh6emcOkpZtRZlbHqtVz5WXZZftm8niId+UXQmJuIQU+YgIiFDmviafapwjaYoXHCv8QMAGqNBP5EWDfxvYyPtGhQrj37sRYpfnUCkdJCiZvZLhQgQ0aIvR3KJIFpXtQmWaaT3e7u07B6weBB7Icto6WflfKtYHvVd1YfOX02/J8byhJbzRY+Qjqrq+5aQR1L3AKbmv8AooZdcm/CrEx6MP7xuIM0fjp1oU4cKQe74KX/KuqE=
10
10
  - secure: fWzpY63ZAXOtjEJuYoya/mwzJ7fZQJGsN6hhamXorOhUgaeP2vdC7/6gK3PPMIXOJ5NXPiANGbAUWKgLLWJ3F7rK2y9UCUWTzvE2CK/13vUV9de7byQfAjfHo7wjDJuPLved+WmSM7ASVjzGq9wQS8MTeYUymSNVY3xiZcvNTO2XY9AAu32SSWDs1ayXiCGE9DyN5WEvEEPixHqpplZLvSqTtKtEZVdP/a3tPuzogYFvoJ/ZEfG9LRr4nnbwuKCaTljpYaZc/8yFbhhJgCrTuOKb0gB/UFeMjd0WX6MQWofzIj152d0ghCTlgtESR2LQJdSXA2BO0ZzSqYj8NKTAcZ8IsaUj+6kBgfQGHu43TF/dB877v8pY55HS8a3gFPDK/6OZhRT7UcFZgle1qvX422CD196fRHktSBcDTx9jQsG8r7Ray9oJygXQr6tKhrRkjMkkBAiBd/GkIJkJu5RecmlLOZMJ+YeYa95kWDUXwo3HGK9MxtFyuplSRYk4mQ1jbrJXdmufQuTazl2FYL+elOUeUb8ej3iniUcmyDGU6tZx84aZTbBOaovmeQqr3pXIaXYMhvkRGLD3Ky7SNZN9ZzFczRWcKStyQal+BYK1R3RU8cD0m0PEpUxV5ERP50E3GyN/0d0bg22LywK9aWDHOhCzjI0emVvSAn8ZiY78SSo=
11
+ - AWS_REGION=eu-central-1
data/ACTIVE_JOB.md ADDED
@@ -0,0 +1,64 @@
1
+ # Sqewer with ActiveJob
2
+
3
+ This gem includes a queue adapter for usage with ActiveJob in Rails 4.2+. The functionality
4
+ is well-tested and should function for any well-conforming ActiveJob subclasses.
5
+
6
+ To run the default `sqewer` worker setup against your Rails application, first set it as the
7
+ executing backend for ActiveJob in your Rails app configuration, set your `SQS_QUEUE_URL`
8
+ in the environment variables, and make sure you can access it using your default (envvar-based
9
+ or machine role based) AWS credentials. Then, set sqewer as the adapter for ActiveJob:
10
+
11
+ class Application < Rails::Application
12
+ ...
13
+ config.active_job.queue_adapter = :sqewer
14
+ end
15
+
16
+ and then run
17
+
18
+ $ bundle exec sqewer_rails
19
+
20
+ in your rails source tree, via a foreman Procfile or similar. If you want to run your own worker binary
21
+ for executing the jobs, be aware that you _have_ to eager-load your Rails application's code explicitly
22
+ before the Sqewer worker is started. The worker is threaded and any kind of autoloading does not generally
23
+ play nice with threading. So do not forget to add this in your worker code:
24
+
25
+ Rails.application.eager_load!
26
+
27
+ For handling error reporting within your Sqewer worker, set up a middleware stack as described in the documentation.
28
+
29
+ ## ActiveJob feature support matrix
30
+
31
+ Compared to the matrix of features as seen in the
32
+ [official ActiveJob documentation](http://edgeapi.rubyonrails.org/classes/ActiveJob/QueueAdapters.html)
33
+ `sqewer` has the following support for various ActiveJob options, in comparison to the builtin
34
+ ActiveJob adapters:
35
+
36
+ | | Async | Queues | Delayed | Priorities | Timeout | Retries |
37
+ |-------------------|-------|--------|------------|------------|---------|---------|
38
+ | sqewer | Yes | No | Yes | No | No | Global |
39
+ | // | // | // | // | // | // | // |
40
+ | Active Job Async | Yes | Yes | Yes | No | No | No |
41
+ | Active Job Inline | No | Yes | N/A | N/A | N/A | N/A |
42
+
43
+ Retries are set up globally for the entire SQS queue. There is no specific queue setting per job,
44
+ since all the messages go to the queue available to `Sqewer.submit!`.
45
+
46
+ There is no timeout handling, if you need it you may want to implement it within your jobs proper.
47
+ Retries are handled on Sqewer level for as many deliveries as your SQS settings permit.
48
+
49
+ ## Delay handling
50
+
51
+ Delayed execution is handled via a combination
52
+ of the `delay_seconds` SQS parameter and the `_execute_after` job key (see the serializer documentation
53
+ in Sqewer for more). In a nutshell - if you postpone a job by less than 900 seconds, the standard delivery
54
+ delay option will be used - and the job will become visible for workers on the SQS queue only after this period.
55
+
56
+ If a larger delay is used, the job will receive an additional field called `_execute_after`, which will contain
57
+ a UNIX timestamp in seconds of when it must be executed at the earliest. In addition, the maximum permitted SQS
58
+ delivery delay will be set for it. If the job then gets redelivered, Sqewer will automatically put it back on the
59
+ queue with the same maximum delay, and will continue doing so for as long as necessary.
60
+
61
+ Note that this will incur extra receives and sends on the queue, and even though it is not substantial,
62
+ it will not be free. We think that this is an acceptable workaround for now, though. If you want a better approach,
63
+ you may be better off using a Rails scheduling system and use a cron job or similar to spin up your enqueue
64
+ for the actual, executable background task.
data/FAQ.md CHANGED
@@ -3,10 +3,6 @@
3
3
  This document tries to answer some questions that may arise when reading or using the library. Hopefully
4
4
  this can provide some answers with regards to how things are put together.
5
5
 
6
- ## Why no ActiveJob?
7
-
8
- An adapter will be added in the future
9
-
10
6
  ## Why separate `new` and `run` methods instead of just `perform`?
11
7
 
12
8
  Because the job needs access to the execution context of the worker. It turned out that keeping the context
data/Gemfile CHANGED
@@ -16,4 +16,8 @@ group :development do
16
16
  gem "rdoc", "~> 3.12"
17
17
  gem "bundler", "~> 1.0"
18
18
  gem "jeweler", "~> 2.0.1"
19
+ gem 'activerecord', '~> 4.2'
20
+ gem 'activejob', '~> 4.2.6'
21
+ gem 'sqlite3'
22
+ # gem 'pry'
19
23
  end
data/README.md CHANGED
@@ -58,6 +58,10 @@ For more detailed usage information, see [DETAILS.md](./DETAILS.md)
58
58
 
59
59
  Please see [FAQ.md](./FAQ.md). This might explain some decisions behind the library in greater detail.
60
60
 
61
+ ## Usage with Rails via ActiveJob
62
+
63
+ Please see [ACTIVE_JOB.md](./ACTIVE_JOB.md) for the exact description.
64
+
61
65
  ## Contributing to the library
62
66
 
63
67
  * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
data/Rakefile CHANGED
@@ -22,6 +22,7 @@ Jeweler::Tasks.new do |gem|
22
22
  gem.summary = %Q{A full-featured library for all them worker needs}
23
23
  gem.email = "me@julik.nl"
24
24
  gem.authors = ["Julik Tarkhanov"]
25
+ gem.executables = ["sqewer", "sqewer_rails"]
25
26
  # dependencies defined in Gemfile
26
27
  end
27
28
  Jeweler::RubygemsDotOrgTasks.new
data/bin/sqewer ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+ require_relative '../lib/sqewer'
3
+
4
+ # Load your application code here:
5
+ # require 'my_application'
6
+
7
+ Sqewer::CLI.start
data/bin/sqewer_rails ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+ require_relative '../lib/sqewer'
3
+ require_relative '../lib/sqewer/extensions/active_job_adapter'
4
+ require_relative '../lib/sqewer/extensions/rails'
5
+
6
+ # Make sure all the classes are preloaded before the threads are spun up
7
+ Rails.application.eager_load!
8
+
9
+ # ...and start
10
+ Sqewer::CLI.start(Sqewer::Worker.new(logger: Rails.logger))
data/lib/sqewer.rb CHANGED
@@ -1,11 +1,28 @@
1
1
  # The enclosing module for the library
2
2
  module Sqewer
3
- Dir.glob(__dir__ + '/**/*.rb').each {|p| require p unless p == __FILE__ }
3
+ # Eager-load everything except extensions
4
+ Dir.glob(__dir__ + '/**/*.rb').each do |path|
5
+ if path != __FILE__ && File.dirname(path) !~ /\/extensions$/
6
+ require path
7
+ end
8
+ end
4
9
 
10
+ # Loads a particular Sqewer extension that is not loaded
11
+ # automatically during the gem require.
12
+ #
13
+ # @param extension_name[String] the name of the extension to load (like `active_job_adapter`)
14
+ def self.require_extension(extension_name)
15
+ path = File.join("sqewer", "extensions", extension_name)
16
+ require_relative path
17
+ end
18
+
5
19
  # Shortcut access to Submitter#submit.
6
20
  #
7
21
  # @see {Sqewer::Submitter#submit!}
8
22
  def self.submit!(*jobs, **options)
9
23
  Sqewer::Submitter.default.submit!(*jobs, **options)
10
24
  end
25
+
26
+ # If we are within Rails, load the railtie
27
+ require_relative 'sqewer/extensions/railtie' if defined?(Rails)
11
28
  end
@@ -5,14 +5,14 @@ class Sqewer::AtomicCounter
5
5
  def initialize
6
6
  @m, @v = Mutex.new, 0
7
7
  end
8
-
8
+
9
9
  # Returns the current value of the counter
10
10
  #
11
11
  # @return [Fixnum] the current value of the counter
12
12
  def to_i
13
13
  @m.synchronize { @v + 0 }
14
14
  end
15
-
15
+
16
16
  # Increments the counter
17
17
  #
18
18
  # @return [Fixnum] the current value of the counter
data/lib/sqewer/cli.rb CHANGED
@@ -20,7 +20,7 @@ module Sqewer::CLI
20
20
  # Signal not supported
21
21
  end
22
22
  end
23
-
23
+
24
24
  begin
25
25
  worker.start
26
26
  # The worker is non-blocking, so in the main CLI process we select() on the signal
@@ -34,7 +34,7 @@ module Sqewer::CLI
34
34
  exit 1
35
35
  end
36
36
  end
37
-
37
+
38
38
  def handle_signal(worker, sig)
39
39
  case sig
40
40
  when 'USR1', 'TERM'
@@ -46,6 +46,6 @@ module Sqewer::CLI
46
46
  raise Interrupt
47
47
  end
48
48
  end
49
-
49
+
50
50
  extend self
51
51
  end
@@ -8,18 +8,18 @@
8
8
  class Sqewer::Connection
9
9
  DEFAULT_TIMEOUT_SECONDS = 5
10
10
  BATCH_RECEIVE_SIZE = 10
11
-
11
+
12
12
  # A wrapper for most important properties of the received message
13
13
  class Message < Struct.new(:receipt_handle, :body)
14
14
  def inspect
15
15
  body.inspect
16
16
  end
17
-
17
+
18
18
  def has_body?
19
19
  body && !body.empty?
20
20
  end
21
21
  end
22
-
22
+
23
23
  # Returns the default adapter, connected to the queue set via the `SQS_QUEUE_URL`
24
24
  # environment variable.
25
25
  def self.default
@@ -27,7 +27,7 @@ class Sqewer::Connection
27
27
  rescue KeyError => e
28
28
  raise "SQS_QUEUE_URL not set in the environment. This is the queue URL that the default that Sqewer uses"
29
29
  end
30
-
30
+
31
31
  # Initializes a new adapter, with access to the SQS queue at the given URL.
32
32
  #
33
33
  # @param queue_url[String] the SQS queue URL (the URL can be copied from your AWS console)
@@ -35,7 +35,7 @@ class Sqewer::Connection
35
35
  require 'aws-sdk'
36
36
  @queue_url = queue_url
37
37
  end
38
-
38
+
39
39
  # Receive at most 10 messages from the queue, and return the array of Message objects.
40
40
  #
41
41
  # @return [Array<Message>] an array of Message objects
@@ -46,7 +46,7 @@ class Sqewer::Connection
46
46
  Message.new(message.receipt_handle, message.body)
47
47
  end
48
48
  end
49
-
49
+
50
50
  # Send a message to the backing queue
51
51
  #
52
52
  # @param message_body[String] the message to send
@@ -56,7 +56,7 @@ class Sqewer::Connection
56
56
  def send_message(message_body, **kwargs_for_send)
57
57
  send_multiple_messages {|via| via.send_message(message_body, **kwargs_for_send) }
58
58
  end
59
-
59
+
60
60
  # Stores the messages for the SQS queue (both deletes and sends), and yields them in allowed batch sizes
61
61
  class MessageBuffer < Struct.new(:messages)
62
62
  MAX_RECORDS = 10
@@ -67,7 +67,7 @@ class Sqewer::Connection
67
67
  messages.each_slice(MAX_RECORDS){|batch| yield(batch)}
68
68
  end
69
69
  end
70
-
70
+
71
71
  # Saves the messages to send to the SQS queue
72
72
  class SendBuffer < MessageBuffer
73
73
  def send_message(message_body, **kwargs_for_send)
@@ -78,7 +78,7 @@ class Sqewer::Connection
78
78
  messages << m
79
79
  end
80
80
  end
81
-
81
+
82
82
  # Saves the receipt handles to batch-delete from the SQS queue
83
83
  class DeleteBuffer < MessageBuffer
84
84
  def delete_message(receipt_handle)
@@ -88,7 +88,7 @@ class Sqewer::Connection
88
88
  messages << m
89
89
  end
90
90
  end
91
-
91
+
92
92
  # Send multiple messages. If any messages fail to send, an exception will be raised.
93
93
  #
94
94
  # @yield [#send_message] the object you can send messages through (will be flushed at method return)
@@ -105,7 +105,7 @@ class Sqewer::Connection
105
105
  end
106
106
  end
107
107
  end
108
-
108
+
109
109
  # Deletes a message after it has been succesfully decoded and processed
110
110
  #
111
111
  # @param message_identifier[String] the ID of the message to delete. For SQS, it is the receipt handle
@@ -113,7 +113,7 @@ class Sqewer::Connection
113
113
  def delete_message(message_identifier)
114
114
  delete_multiple_messages {|via| via.delete_message(message_identifier) }
115
115
  end
116
-
116
+
117
117
  # Deletes multiple messages after they all have been succesfully decoded and processed.
118
118
  #
119
119
  # @yield [#delete_message] an object you can delete an individual message through
@@ -121,7 +121,7 @@ class Sqewer::Connection
121
121
  def delete_multiple_messages
122
122
  buffer = DeleteBuffer.new
123
123
  yield(buffer)
124
-
124
+
125
125
  buffer.each_batch do | batch |
126
126
  resp = client.delete_message_batch(queue_url: @queue_url, entries: batch)
127
127
  failed = resp.failed
@@ -131,9 +131,9 @@ class Sqewer::Connection
131
131
  end
132
132
  end
133
133
  end
134
-
134
+
135
135
  private
136
-
136
+
137
137
  class RetryWrapper < Struct.new(:sqs_client)
138
138
  MAX_RETRIES = 1000
139
139
  # Provide retrying wrappers for all the methods of Aws::SQS::Client that we actually use
@@ -153,7 +153,7 @@ class Sqewer::Connection
153
153
  end
154
154
  end
155
155
  end
156
-
156
+
157
157
  def client
158
158
  @client ||= RetryWrapper.new(Aws::SQS::Client.new)
159
159
  end
@@ -23,7 +23,7 @@ class Sqewer::ConnectionMessagebox
23
23
  @sends = []
24
24
  @mux = Mutex.new
25
25
  end
26
-
26
+
27
27
  # Saves the given body and the keyword arguments (such as delay_seconds) to be sent into the queue.
28
28
  # If there are more sends in the same flush, they will be batched using batched deletes.G
29
29
  #
@@ -33,7 +33,7 @@ class Sqewer::ConnectionMessagebox
33
33
  @sends << [message_body, kwargs_for_send]
34
34
  }
35
35
  end
36
-
36
+
37
37
  # Saves the given identifier to be deleted from the queue. If there are more
38
38
  # deletes in the same flush, they will be batched using batched deletes.
39
39
  #
@@ -43,7 +43,7 @@ class Sqewer::ConnectionMessagebox
43
43
  @deletes << message_identifier
44
44
  }
45
45
  end
46
-
46
+
47
47
  # Flushes all the accumulated commands to the queue connection.
48
48
  # First the message sends are going to be flushed, then the message deletes.
49
49
  # All of those will use batching where possible.
@@ -52,7 +52,7 @@ class Sqewer::ConnectionMessagebox
52
52
  @connection.send_multiple_messages do | buffer |
53
53
  @sends.each { |body, kwargs| buffer.send_message(body, **kwargs) }
54
54
  end
55
-
55
+
56
56
  @connection.delete_multiple_messages do | buffer |
57
57
  @deletes.each { |id| buffer.delete_message(id) }
58
58
  end
@@ -14,14 +14,14 @@ class Sqewer::ExecutionContext
14
14
  @params = {}
15
15
  extra_variables.each_pair{|k, v| self[k] = v }
16
16
  end
17
-
17
+
18
18
  # Submits one or more jobs to the queue
19
19
  #
20
20
  # @see {Sqewer::Submitter#submit!}
21
21
  def submit!(job, **execution_options)
22
22
  @submitter.submit!(job, **execution_options)
23
23
  end
24
-
24
+
25
25
  # Sets a key in the execution environment
26
26
  #
27
27
  # @param key[#to_s] the key to set
@@ -29,14 +29,14 @@ class Sqewer::ExecutionContext
29
29
  def []=(key, value)
30
30
  @params[key.to_s] = value
31
31
  end
32
-
32
+
33
33
  # Returns a key of the execution environment by name
34
34
  #
35
35
  # @param key[#to_s] the key to get
36
36
  def [](key)
37
37
  @params[key.to_s]
38
38
  end
39
-
39
+
40
40
  # Returns a key of the execution environment, or executes the given block
41
41
  # if the key is not set
42
42
  #
@@ -45,7 +45,7 @@ class Sqewer::ExecutionContext
45
45
  def fetch(key, &blk)
46
46
  @params.fetch(key.to_s, &blk)
47
47
  end
48
-
48
+
49
49
  # Returns the logger set in the execution environment, or
50
50
  # the NullLogger if no logger is set. Can be used to supply
51
51
  # a logger prefixed with job parameters per job.
@@ -0,0 +1,78 @@
1
+ # ActiveJob docs: http://edgeguides.rubyonrails.org/active_job_basics.html
2
+ # Example adapters ref: https://github.com/rails/rails/tree/master/activejob/lib/active_job/queue_adapters
3
+ module ActiveJob
4
+ module QueueAdapters
5
+
6
+ # Handle Rails ActiveJob through sqewer.
7
+ # Set it up like so:
8
+ #
9
+ # Rails.application.config.active_job.queue_adapter = :sqewer
10
+ class SqewerAdapter
11
+ # Works as a Job for sqewer, and wraps an ActiveJob Worker which responds to perform()
12
+ class Performable
13
+
14
+ # Creates a new Performable using the passed ActiveJob object. The resulting Performable
15
+ # can be sent to any Sqewer queue.
16
+ #
17
+ # @param active_job_worker[ActiveJob::Job] the job you want to convert
18
+ def self.from_active_job(active_job_worker)
19
+ # Try to grab the job class immediately, so that an error is raised in the unserializer
20
+ # if the class is not available
21
+ klass = active_job_worker.class.to_s
22
+ Kernel.const_get(klass)
23
+ new(job: active_job_worker.serialize)
24
+ end
25
+
26
+ def initialize(job:)
27
+ @job = job
28
+ end
29
+
30
+ def to_h
31
+ {job: @job}
32
+ end
33
+
34
+ def inspect
35
+ '<%s>' % [@job.inspect]
36
+ end
37
+
38
+ # Runs the contained ActiveJob.
39
+ def run
40
+ job = ActiveSupport::HashWithIndifferentAccess.new(@job)
41
+ if active_record_defined_and_connected?
42
+ with_active_record_connection_from_pool { Base.execute(job) }
43
+ else
44
+ Base.execute(job)
45
+ end
46
+ end
47
+
48
+ private
49
+
50
+ def with_active_record_connection_from_pool
51
+ ActiveRecord::Base.connection_pool.with_connection { yield }
52
+ end
53
+
54
+ def active_record_defined_and_connected?
55
+ defined?(ActiveRecord) && ActiveRecord::Base.connected?
56
+ end
57
+
58
+ end
59
+
60
+ class << self
61
+ def enqueue(active_job) #:nodoc:
62
+ wrapped_job = Performable.from_active_job(active_job)
63
+
64
+ Sqewer.submit!(wrapped_job)
65
+ end
66
+
67
+ def enqueue_at(active_job, timestamp) #:nodoc:
68
+ wrapped_job = Performable.from_active_job(active_job)
69
+
70
+ delta_t = (timestamp - Time.now.to_i).to_i
71
+
72
+ Sqewer.submit!(wrapped_job, delay_seconds: delta_t)
73
+ end
74
+ end
75
+
76
+ end
77
+ end
78
+ end