aboutsummaryrefslogtreecommitdiffstats
path: root/activejob
diff options
context:
space:
mode:
Diffstat (limited to 'activejob')
-rw-r--r--activejob/CHANGELOG.md4
-rw-r--r--activejob/activejob.gemspec2
-rw-r--r--activejob/lib/active_job/arguments.rb5
-rw-r--r--activejob/lib/active_job/queue_adapters.rb71
-rw-r--r--activejob/lib/rails/generators/job/job_generator.rb1
-rw-r--r--activejob/lib/rails/generators/job/templates/job.rb2
-rw-r--r--activejob/test/integration/queuing_test.rb4
-rw-r--r--activejob/test/support/integration/adapters/que.rb24
-rw-r--r--activejob/test/support/integration/adapters/queue_classic.rb22
-rw-r--r--activejob/test/support/integration/adapters/sidekiq.rb80
10 files changed, 164 insertions, 51 deletions
diff --git a/activejob/CHANGELOG.md b/activejob/CHANGELOG.md
index d4e19274fa..85a437a1dd 100644
--- a/activejob/CHANGELOG.md
+++ b/activejob/CHANGELOG.md
@@ -1,3 +1,7 @@
+* A generated job now inherents from `app/jobs/application_job.rb` by default.
+
+ *Jeroen van Baarsen*
+
* Add an `:only` option to `perform_enqueued_jobs` to filter jobs based on
type.
diff --git a/activejob/activejob.gemspec b/activejob/activejob.gemspec
index ef8db3bcd3..24e38e495f 100644
--- a/activejob/activejob.gemspec
+++ b/activejob/activejob.gemspec
@@ -7,7 +7,7 @@ Gem::Specification.new do |s|
s.summary = 'Job framework with pluggable queues.'
s.description = 'Declare job classes that can be run by a variety of queueing backends.'
- s.required_ruby_version = '>= 2.2.1'
+ s.required_ruby_version = '>= 2.2.2'
s.license = 'MIT'
diff --git a/activejob/lib/active_job/arguments.rb b/activejob/lib/active_job/arguments.rb
index 622c37098e..f9392cf278 100644
--- a/activejob/lib/active_job/arguments.rb
+++ b/activejob/lib/active_job/arguments.rb
@@ -24,6 +24,7 @@ module ActiveJob
module Arguments
extend self
+ # :nodoc:
TYPE_WHITELIST = [ NilClass, Fixnum, Float, String, TrueClass, FalseClass, Bignum ]
# Serializes a set of arguments. Whitelisted types are returned
@@ -43,8 +44,11 @@ module ActiveJob
end
private
+ # :nodoc:
GLOBALID_KEY = '_aj_globalid'.freeze
+ # :nodoc:
SYMBOL_KEYS_KEY = '_aj_symbol_keys'.freeze
+ # :nodoc:
WITH_INDIFFERENT_ACCESS_KEY = '_aj_hash_with_indifferent_access'.freeze
private_constant :GLOBALID_KEY, :SYMBOL_KEYS_KEY, :WITH_INDIFFERENT_ACCESS_KEY
@@ -113,6 +117,7 @@ module ActiveJob
result
end
+ # :nodoc:
RESERVED_KEYS = [
GLOBALID_KEY, GLOBALID_KEY.to_sym,
SYMBOL_KEYS_KEY, SYMBOL_KEYS_KEY.to_sym,
diff --git a/activejob/lib/active_job/queue_adapters.rb b/activejob/lib/active_job/queue_adapters.rb
index b3d91dc562..bd69e525bb 100644
--- a/activejob/lib/active_job/queue_adapters.rb
+++ b/activejob/lib/active_job/queue_adapters.rb
@@ -27,13 +27,76 @@ module ActiveJob
# | Sneakers | Yes | Yes | No | Queue | Queue | No |
# | Sucker Punch | Yes | Yes | No | No | No | No |
# | Active Job Inline | No | Yes | N/A | N/A | N/A | N/A |
- # | Active Job | Yes | Yes | Yes | No | No | No |
+ #
+ # ==== Async
+ #
+ # Yes: The Queue Adapter runs the jobs in a separate or forked process.
+ #
+ # No: The job is run in the same process.
+ #
+ # ==== Queues
+ #
+ # Yes: Jobs may set which queue they are run in with queue_as or by using the set
+ # method.
+ #
+ # ==== Delayed
+ #
+ # Yes: The adapter will run the job in the future through perform_later.
+ #
+ # (Gem): An additional gem is required to use perform_later with this adapter.
+ #
+ # No: The adapter will run jobs at the next opportunity and cannot use perform_later.
+ #
+ # N/A: The adapter does not support queueing.
#
# NOTE:
- # queue_classic does not support Job scheduling. However you can implement this
- # yourself or you can use the queue_classic-later gem. See the documentation for
- # ActiveJob::QueueAdapters::QueueClassicAdapter.
+ # queue_classic does not support job scheduling.
+ # However, you can use the queue_classic-later gem.
+ # See the documentation for ActiveJob::QueueAdapters::QueueClassicAdapter.
+ #
+ # ==== Priorities
+ #
+ # The order in which jobs are processed can be configured differently depending
+ # on the adapter.
+ #
+ # Job: Any class inheriting from the adapter may set the priority on the job
+ # object relative to other jobs.
+ #
+ # Queue: The adapter can set the priority for job queues, when setting a queue
+ # with Active Job this will be respected.
+ #
+ # Yes: Allows the priority to be set on the job object, at the queue level or
+ # as default configuration option.
+ #
+ # No: Does not allow the priority of jobs to be configured.
+ #
+ # N/A: The adapter does not support queueing, and therefore sorting them.
+ #
+ # ==== Timeout
+ #
+ # When a job will stop after the allotted time.
+ #
+ # Job: The timeout can be set for each instance of the job class.
+ #
+ # Queue: The timeout is set for all jobs on the queue.
+ #
+ # Global: The adapter is configured that all jobs have a maximum run time.
+ #
+ # N/A: This adapter does not run in a separate process, and therefore timeout
+ # is unsupported.
+ #
+ # ==== Retries
+ #
+ # Job: The number of retries can be set per instance of the job class.
+ #
+ # Yes: The Number of retries can be configured globally, for each instance or
+ # on the queue. This adapter may also present failed instances of the job class
+ # that can be restarted.
+ #
+ # Global: The adapter has a global number of retries.
#
+ # N/A: The adapter does not run in a separate process, and therefore doesn't
+ # support retries.
module QueueAdapters
extend ActiveSupport::Autoload
diff --git a/activejob/lib/rails/generators/job/job_generator.rb b/activejob/lib/rails/generators/job/job_generator.rb
index 979ffcb748..86e4c5266c 100644
--- a/activejob/lib/rails/generators/job/job_generator.rb
+++ b/activejob/lib/rails/generators/job/job_generator.rb
@@ -18,7 +18,6 @@ module Rails
def create_job_file
template 'job.rb', File.join('app/jobs', class_path, "#{file_name}_job.rb")
end
-
end
end
end
diff --git a/activejob/lib/rails/generators/job/templates/job.rb b/activejob/lib/rails/generators/job/templates/job.rb
index 462c71d917..4ad2914a45 100644
--- a/activejob/lib/rails/generators/job/templates/job.rb
+++ b/activejob/lib/rails/generators/job/templates/job.rb
@@ -1,5 +1,5 @@
<% module_namespacing do -%>
-class <%= class_name %>Job < ActiveJob::Base
+class <%= class_name %>Job < ApplicationJob
queue_as :<%= options[:queue] %>
def perform(*args)
diff --git a/activejob/test/integration/queuing_test.rb b/activejob/test/integration/queuing_test.rb
index af19a92118..09f5c329cc 100644
--- a/activejob/test/integration/queuing_test.rb
+++ b/activejob/test/integration/queuing_test.rb
@@ -26,8 +26,6 @@ class QueuingTest < ActiveSupport::TestCase
test 'should supply a wrapped class name to Sidekiq' do
skip unless adapter_is?(:sidekiq)
- require 'sidekiq/testing'
-
Sidekiq::Testing.fake! do
::HelloJob.perform_later
hash = ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper.jobs.first
@@ -48,7 +46,7 @@ class QueuingTest < ActiveSupport::TestCase
test 'should run job enqueued in the future at the specified time' do
begin
- TestJob.set(wait: 3.seconds).perform_later @id
+ TestJob.set(wait: 5.seconds).perform_later @id
wait_for_jobs_to_finish_for(2.seconds)
assert_not job_executed
wait_for_jobs_to_finish_for(10.seconds)
diff --git a/activejob/test/support/integration/adapters/que.rb b/activejob/test/support/integration/adapters/que.rb
index ba7657a42a..ff5235bdc8 100644
--- a/activejob/test/support/integration/adapters/que.rb
+++ b/activejob/test/support/integration/adapters/que.rb
@@ -2,6 +2,15 @@ module QueJobsManager
def setup
require 'sequel'
ActiveJob::Base.queue_adapter = :que
+ Que.mode = :off
+ Que.worker_count = 1
+ end
+
+ def clear_jobs
+ Que.clear!
+ end
+
+ def start_workers
que_url = ENV['QUE_DATABASE_URL'] || 'postgres:///active_jobs_que_int_test'
uri = URI.parse(que_url)
user = uri.user||ENV['USER']
@@ -11,24 +20,17 @@ module QueJobsManager
%x{#{"PGPASSWORD=\"#{pass}\"" if pass} psql -c 'create database "#{db}"' -U #{user} -t template1}
Que.connection = Sequel.connect(que_url)
Que.migrate!
- Que.mode = :off
- Que.worker_count = 1
- rescue Sequel::DatabaseConnectionError
- puts "Cannot run integration tests for que. To be able to run integration tests for que you need to install and start postgresql.\n"
- exit
- end
-
- def clear_jobs
- Que.clear!
- end
- def start_workers
@thread = Thread.new do
loop do
Que::Job.work("integration_tests")
sleep 0.5
end
end
+
+ rescue Sequel::DatabaseConnectionError
+ puts "Cannot run integration tests for que. To be able to run integration tests for que you need to install and start postgresql.\n"
+ exit
end
def stop_workers
diff --git a/activejob/test/support/integration/adapters/queue_classic.rb b/activejob/test/support/integration/adapters/queue_classic.rb
index f522b2711f..29c04bf625 100644
--- a/activejob/test/support/integration/adapters/queue_classic.rb
+++ b/activejob/test/support/integration/adapters/queue_classic.rb
@@ -3,17 +3,7 @@ module QueueClassicJobsManager
ENV['QC_DATABASE_URL'] ||= 'postgres:///active_jobs_qc_int_test'
ENV['QC_RAILS_DATABASE'] = 'false'
ENV['QC_LISTEN_TIME'] = "0.5"
- uri = URI.parse(ENV['QC_DATABASE_URL'])
- user = uri.user||ENV['USER']
- pass = uri.password
- db = uri.path[1..-1]
- %x{#{"PGPASSWORD=\"#{pass}\"" if pass} psql -c 'drop database if exists "#{db}"' -U #{user} -t template1}
- %x{#{"PGPASSWORD=\"#{pass}\"" if pass} psql -c 'create database "#{db}"' -U #{user} -t template1}
ActiveJob::Base.queue_adapter = :queue_classic
- QC::Setup.create
- rescue PG::ConnectionBad
- puts "Cannot run integration tests for queue_classic. To be able to run integration tests for queue_classic you need to install and start postgresql.\n"
- exit
end
def clear_jobs
@@ -21,12 +11,24 @@ module QueueClassicJobsManager
end
def start_workers
+ uri = URI.parse(ENV['QC_DATABASE_URL'])
+ user = uri.user||ENV['USER']
+ pass = uri.password
+ db = uri.path[1..-1]
+ %x{#{"PGPASSWORD=\"#{pass}\"" if pass} psql -c 'drop database if exists "#{db}"' -U #{user} -t template1}
+ %x{#{"PGPASSWORD=\"#{pass}\"" if pass} psql -c 'create database "#{db}"' -U #{user} -t template1}
+ QC::Setup.create
+
QC.default_conn_adapter.disconnect
QC.default_conn_adapter = nil
@pid = fork do
worker = QC::Worker.new(q_name: 'integration_tests')
worker.start
end
+
+ rescue PG::ConnectionBad
+ puts "Cannot run integration tests for queue_classic. To be able to run integration tests for queue_classic you need to install and start postgresql.\n"
+ exit
end
def stop_workers
diff --git a/activejob/test/support/integration/adapters/sidekiq.rb b/activejob/test/support/integration/adapters/sidekiq.rb
index 6ff18fb56a..4988cdb33f 100644
--- a/activejob/test/support/integration/adapters/sidekiq.rb
+++ b/activejob/test/support/integration/adapters/sidekiq.rb
@@ -1,6 +1,8 @@
-require 'sidekiq/cli'
require 'sidekiq/api'
+require 'sidekiq/testing'
+Sidekiq::Testing.disable!
+
module SidekiqJobsManager
def setup
@@ -17,33 +19,71 @@ module SidekiqJobsManager
end
def start_workers
- fork do
- sidekiq = Sidekiq::CLI.instance
+ continue_read, continue_write = IO.pipe
+ death_read, death_write = IO.pipe
+
+ @pid = fork do
+ continue_read.close
+ death_write.close
+
+ # Celluloid & Sidekiq are not warning-clean :(
+ $VERBOSE = false
+
+ $stdin.reopen('/dev/null')
+ $stdout.sync = true
+ $stderr.sync = true
+
logfile = Rails.root.join("log/sidekiq.log").to_s
- pidfile = Rails.root.join("tmp/sidekiq.pid").to_s
- sidekiq.parse([ "--require", Rails.root.to_s,
- "--queue", "integration_tests",
- "--logfile", logfile,
- "--pidfile", pidfile,
- "--environment", "test",
- "--concurrency", "1",
- "--timeout", "1",
- "--daemon",
- ])
+ Sidekiq::Logging.initialize_logger(logfile)
+
+ self_read, self_write = IO.pipe
+ trap "TERM" do
+ self_write.puts("TERM")
+ end
+
+ Thread.new do
+ begin
+ death_read.read
+ rescue Exception
+ end
+ self_write.puts("TERM")
+ end
+
require 'celluloid'
- require 'sidekiq/scheduled'
+ Celluloid.logger = nil
+ require 'sidekiq/launcher'
+ sidekiq = Sidekiq::Launcher.new({queues: ["integration_tests"],
+ environment: "test",
+ concurrency: 1,
+ timeout: 1,
+ })
Sidekiq.poll_interval = 0.5
Sidekiq::Scheduled.const_set :INITIAL_WAIT, 1
- sidekiq.run
+ begin
+ sidekiq.run
+ continue_write.puts "started"
+ while readable_io = IO.select([self_read])
+ signal = readable_io.first[0].gets.strip
+ raise Interrupt if signal == "TERM"
+ end
+ rescue Interrupt
+ end
+
+ sidekiq.stop
+ exit!
end
- sleep 1
+ continue_write.close
+ death_read.close
+ @worker_lifeline = death_write
+
+ raise "Failed to start worker" unless continue_read.gets == "started\n"
end
def stop_workers
- pidfile = Rails.root.join("tmp/sidekiq.pid").to_s
- Process.kill 'TERM', File.open(pidfile).read.to_i
- FileUtils.rm_f pidfile
- rescue
+ if @pid
+ Process.kill 'TERM', @pid
+ Process.wait @pid
+ end
end
def can_run?