Commit Graph

781 Commits

Author SHA1 Message Date
Daniel Morton ee60ce5606 Communicate enqueue failures to callers of perform_later
There is presently no clean way of telling a caller of `perform_later`
the reason why a job failed to enqueue. When the job is enqueued
successfully, the job object itself is returned, but when the job can
not be enqueued, only `false` is returned. This does not allow callers
to distinguish between classes of failures.

One important class of failures is when the job backend experiences a
network partition when communicating with its underlying datastore. It
is entirely possible for that network partition to recover and as such,
code attempting to enqueue a job may wish to take action to reenqueue
that job after a brief delay. This is distinguished from the class of
failures where due a business rule defined in a callback in the
application, a job fails to enqueue and should not be retried.

This PR changes the following:

- Allows a block to be passed to the `perform_later` method. After the
  `enqueue` method is executed, but before the result is returned, the
  job will be yielded to the block. This allows the code invoking the
  `perform_later` method to inspect the job object, even in failure
  scenarios.

- Adds an exception `EnqueueError` which job adapters can raise if they
  detect a problem specific to their underlying implementation or
  infrastructure during the enqueue process.

- Adds two properties to the job base class: `successfully_enqueued` and
  `enqueue_error`. `enqueue_error` will be populated by the `enqueue`
  method if it rescues an `EnqueueError` raised by the job backend.
  `successfully_enqueued` will be true if the job is not rejected by
  callbacks and does not cause the job backend to raise an
  `EnqueueError` and will be `false` otherwise.

This will allow developers to do something like the following:

    MyJob.perform_later do |job|
      unless job.successfully_enqueued?
        if job.enqueue_error&.message == "Redis was unavailable"
          # invoke some code that will retry the job after a delay
        end
      end
    end
2021-02-05 16:32:43 -05:00
Rafael Mendonça França 1b455e2e9d
Rails 6.2 is now Rails 7.0
We have big plans for the next version of Rails and that
require big versions.
2021-02-04 16:47:16 +00:00
Rafael Mendonça França 6487836af8
Rails 7 requires Ruby 2.7 and prefer Ruby 3+
The code cleanup is comming in later commits but this
already remove support to Ruby < 2.7.
2021-02-04 16:34:53 +00:00
Pedro Chambino d318af93c5
Add missing require to ActiveJob::TestHelper
Following PR #40780, it now fails after requiring active_job:

    irb(main):001:0> require 'active_job'
    => true
    irb(main):002:0> ActiveJob::VERSION::STRING
    => "6.1.1"
    irb(main):003:0> ActiveJob::TestHelper
    [redacted]
    NameError (uninitialized constant ActiveSupport::Testing)
2021-02-02 11:50:54 +00:00
Rafael Mendonça França bea721aa91
Merge remote-tracking branch 'origin/main' into skip-logging-rescuable-exceptions 2021-02-02 01:09:06 +00:00
Rafael Mendonça França efa64bb295
Refactor the code to keep instrumentation and log inside the modules
Use inheritance to keep the behavior in the right modules.

The order of Instrumentation and Logging had to change to be
flipped to keep the current behavior.
2021-02-02 01:07:24 +00:00
Étienne Barrié 142ae54e54 Allow jobs to rescue all exceptions
Before this commit, only StandardError exceptions can be handled by
rescue_from handlers.

This changes the rescue clause to catch all Exception objects, allowing
rescue handlers to be defined for Exception classes not inheriting from
StandardError.

This means that rescue handlers that are rescuing Exceptions outside of
StandardError exceptions may rescue exceptions that were not being
rescued before this change.

Co-authored-by: Adrianna Chang <adrianna.chang@shopify.com>
2021-01-23 08:35:51 -05:00
Rafael Mendonça França 077c66d5d6
Rename master to main in all code references 2021-01-19 20:46:33 +00:00
Ryuta Kamizono 2b0b5a75c0 Bump license years to 2021 [ci skip] 2021-01-01 12:21:20 +09:00
HU Hailin b8baeb44ae change the `perform` instrumentation to wrap `perform_now` instead of the `perform` method. 2020-12-31 11:13:03 +09:00
HU Hailin 0c6f32a9f9 Skip logging rescuable exceptions which are defined in rescue_from/retry_on/discard_on.
Update activejob/CHANGELOG.md

Co-authored-by: Rafael França <rafael@franca.dev>
2020-12-31 11:12:58 +09:00
Rafael Mendonça França 68b471c4dd
Make sure job instrumentation keep return value
The implementaiton of `instrument` in `ActiveJob::Instrumentation` was
not keeping the API of `ActiveSupport::Notification.instrument` and
returning the value of the block.

Fixes #40931.
2020-12-28 05:30:30 +00:00
Rafael França 96db850d51
Merge pull request #40780 from mikker/mikker-assert-nothing-raised-fix
Include ActiveSupport::Testing::Assertions in ActiveJob::TestHelpers
2020-12-18 17:12:38 -05:00
George Claghorn c89632abf0 Revert "Merge pull request #39472"
This change broke config.active_job.queue_name_prefix with eager-loading enabled (i.e. in production, by default).

This reverts commit a173a65730, reversing
changes made to 89414f561a.
2020-12-17 19:27:14 -05:00
Mikkel Malmberg a9f78ebc16
Whitespace 2020-12-10 11:53:34 +01:00
Mikkel Malmberg 5cb90b1b71
Include ActiveSupport::Testing::Assertions in ActiveJob::TestHelpers
After upgrading to Rails 6.1 I'm getting a `undefined method `assert_nothing_raised'` using `ActiveJob::TestHelpers` and `assert_enqueued_jobs` in RSpec.

Adding this module fixes it, however not knowing the internals too well, I'm unsure whether it's the right fix.
2020-12-10 11:47:17 +01:00
Rafael França a8f0fcc6ad
Merge pull request #40754 from yahonda/revert_workarounds_for_ruby_17220
Revert 'sleep 1' workarounds since Ruby issue 17220 has been addressed
2020-12-08 13:59:33 -05:00
KapilSachdev a908d06c85
feat(rubocop): Add Style/RedundantRegexpEscape
- This cop will help in removing unnecessary escaping inside Regexp literals.
2020-12-08 18:57:09 +00:00
Yasuo Honda aa026ee105 Revert "Work around getaddrinfo deadlock in forked process"
This reverts commit 7cf8e30902.
2020-12-06 23:01:56 +09:00
Yasuo Honda 8ae1738a14 Revert "Merge pull request #40451 from yahonda/sneakers"
This reverts commit 3b9807f3de, reversing
changes made to 7e2d8434ed.
2020-12-06 23:01:41 +09:00
Yasuo Honda fa3d47018b Revert "Merge pull request #40453 from yahonda/resque_start_workers"
This reverts commit 1fddc8023e, reversing
changes made to 1f5a4d1d5e.
2020-12-06 23:01:19 +09:00
Rafael Mendonça França 59f7f5889e
Start Rails 6.2 development 🎉 2020-12-03 01:35:29 +00:00
Rafael Mendonça França a173a65730
Merge pull request #39472
Closes #39472.
2020-12-01 00:40:52 +00:00
Rafael França 90fa01b4c0
Merge pull request #40626 from jonathanhefner/executor-wrap-db-seeds
Wrap evaluation of db/seeds.rb with the executor
2020-11-24 15:01:22 -05:00
Jonathan Hefner 648da12519 Wrap evaluation of db/seeds.rb with the executor
Before #34953, when using the `:async` Active Job queue adapter, jobs
enqueued in `db/seeds.rb`, such as Active Storage analysis jobs, would
cause a hang (see #34939).  Therefore, #34953 changed all jobs enqueued
in `db/seeds.rb` to use the `:inline` queue adapter instead.  (This
behavior was later limited to only take effect when the `:async` adapter
was configured, see #35905.)  However, inline jobs in `db/seeds.rb`
cleared `CurrentAttributes` values (see #37526).  Therefore, #37568
changed the `:inline` adapter to wrap each job in its own thread, for
isolation.  However, wrapping a job in its own thread affects which
database connection it uses.  Thus inline jobs can no longer execute
within the calling thread's database transaction, including seeing any
uncommitted changes.  Additionally, if the calling thread is not wrapped
with the executor, the inline job thread (which is wrapped with the
executor) can deadlock on the load interlock.  And when testing (with
`connection_pool.lock_thread = true`), the inline job thread can
deadlock on one of the locks added by #28083.

Therefore, this commit reverts the solutions of #34953 and #37568, and
instead wraps evaluation of `db/seeds.rb` with the executor.  This
eliminates the original hang from #34939, which was also due to running
multiple threads and not wrapping all of them with the executor.  And,
because nested calls to `executor.wrap` are ignored, any inline jobs in
`db/seeds.rb` will not clear `CurrentAttributes` values.

Alternative fix for #34939.
Reverts #34953.
Reverts #35905.
Partially reverts #35896.

Alternative fix for #37526.
Reverts #37568.

Fixes #40552.
2020-11-18 16:26:20 -06:00
Eugene Kenny 65d7aa5811 Reset Time.zone to avoid leaking into other tests
https://buildkite.com/rails/rails/builds/72478#93358e11-6e26-4588-a791-26f9512157c2/1074-1087
https://buildkite.com/rails/rails/builds/72747#10657eba-2359-47ca-9914-49a48b3f2d3c/967-976
https://buildkite.com/rails/rails/builds/72795#3f4bff27-3f42-4678-b643-08cc811c8954/999-1012
2020-11-15 01:02:22 +00:00
Ryuta Kamizono 53331b478d Fix typos [ci skip] 2020-11-09 15:23:39 +09:00
Rafael Mendonça França 8389f9902c
Preparing for 6.1.0.rc1 release 2020-11-02 21:12:47 +00:00
Rafael França 45a1bcea9b
Merge pull request #39532 from vipulnsward/fix-tz-perform-now
Set timezone on a Job initialization to make it conform more with perform_later when doing JobClass.perform_now
2020-10-30 16:42:29 -04:00
Guo Xiang Tan bda10bf3a8
Recover precision when serializing `Time`, `TimeWithZone` and `DateTime`. 2020-10-30 19:58:13 +00:00
Rafael Mendonça França fd24cf1c5d
Return `false` when enqueuing a job is aborted 2020-10-30 00:25:31 +00:00
Yasuo Honda a0561d746d Workaround Active Job integration test with resque against ruby 3.0.0dev
This pull request workarounds Active Job integration test with `resque` reported at https://buildkite.com/rails/rails/builds/72277#410533b8-0676-4ad2-900f-fa8131f9833f/1826
This fix is similar to 7cf8e30 and rails/rails#40451 which is due to https://bugs.ruby-lang.org/issues/17220

- Steps to reproduce

```
- Install Docker
$ git clone https://github.com/rails/rails
$ cd rails
$ git clone https://github.com/rails/buildkite-config .buildkite/
$ RUBY_IMAGE=rubylang/ruby:master-nightly-bionic docker-compose -f .buildkite/docker-compose.yml build base && CI=1 docker-compose -f .buildkite/docker-compose.yml run activejob runner activejob 'AJ_ADAPTER=resque AJ_INTEGRATION_TESTS=true bin/test test/integration/queuing_test.rb  --seed 36344'
```

- Without this commit

```
$ RUBY_IMAGE=rubylang/ruby:master-nightly-bionic docker-compose -f .buildkite/docker-compose.yml build base && CI=1 docker-compose -f .buildkite/docker-compose.yml run activejob runner activejob 'AJ_ADAPTER=resque AJ_INTEGRATION_TESTS=true bin/test test/integration/queuing_test.rb  --seed 36344'
... snip ...
+++ activejob: AJ_ADAPTER=resque AJ_INTEGRATION_TESTS=true bin/test test/integration/queuing_test.rb  --seed 36344
Using resque
/usr/local/lib/ruby/gems/3.0.0/gems/resque-scheduler-4.4.0/lib/resque/scheduler/lock/base.rb:50: warning: Socket.gethostbyname is deprecated; use Addrinfo.getaddrinfo instead.
Run options: --seed 36344

.F

Failure:
QueuingTest#test_should_run_jobs_enqueued_on_a_listening_queue [/rails/activejob/test/integration/queuing_test.rb:14]:
Expected false to be truthy.

bin/test test/integration/queuing_test.rb:11

F

Failure:
QueuingTest#test_current_timezone_is_kept_while_running_perform_later [/rails/activejob/test/integration/queuing_test.rb:119]:
Expected false to be truthy.

bin/test test/integration/queuing_test.rb:110

.SSF

Failure:
QueuingTest#test_current_locale_is_kept_while_running_perform_later [/rails/activejob/test/integration/queuing_test.rb:102]:
Expected false to be truthy.

bin/test test/integration/queuing_test.rb:93

.F

Failure:
QueuingTest#test_should_run_job_enqueued_in_the_future_at_the_specified_time [/rails/activejob/test/integration/queuing_test.rb:76]:
Expected false to be truthy.

bin/test test/integration/queuing_test.rb:71

SSSSSS

Finished in 34.122641s, 0.4396 runs/s, 0.2344 assertions/s.
15 runs, 8 assertions, 4 failures, 0 errors, 8 skips

You have skipped tests. Run with --verbose for details.
$
```

- With this commit

```ruby
$ RUBY_IMAGE=rubylang/ruby:master-nightly-bionic docker-compose -f .buildkite/docker-compose.yml build base && CI=1 docker-compose -f .buildkite/docker-compose.yml run activejob runner activejob 'AJ_ADAPTER=resque AJ_INTEGRATION_TESTS=true bin/test test/integration/queuing_test.rb  --seed 36344'
... snip ...
+++ activejob: AJ_ADAPTER=resque AJ_INTEGRATION_TESTS=true bin/test test/integration/queuing_test.rb  --seed 36344
Using resque
/usr/local/lib/ruby/gems/3.0.0/gems/resque-scheduler-4.4.0/lib/resque/scheduler/lock/base.rb:50: warning: Socket.gethostbyname is deprecated; use Addrinfo.getaddrinfo instead.
Run options: --seed 36344

....SS...SSSSSS

Finished in 13.850658s, 1.0830 runs/s, 0.7220 assertions/s.
15 runs, 10 assertions, 0 failures, 0 errors, 8 skips

You have skipped tests. Run with --verbose for details.
$
```
2020-10-25 23:50:55 +09:00
Yasuo Honda 9f4818c55f Address Active Job integration test with sneakers against ruby 3.0.0dev
This pull request addresses Active Job integration test with `sneakers` reported at https://buildkite.com/rails/rails/builds/72257#20014e66-6e08-47ae-a827-b71de7148306/2017
This fix is similar to 7cf8e30902 which is due to https://bugs.ruby-lang.org/issues/17220

- Steps to reproduce
Install ruby 3.0.0dev using ruby-build or whatever then execute these steps.

```ruby
$ git clone https://github.com/rails/rails
$ cd rails/activejob
$ bundle install
$ bundle exec rake test:integration:sneakers
```

- Result without this commit

```ruby
$ ruby -v
ruby 3.0.0dev (2020-10-24T13:53:53Z master 148961adcd) [x86_64-linux]
$ cd activejob
$ bundle exec rake test:integration:sneakers
... snip ...
/home/yahonda/src/github.com/rails/rails/activejob/test/support/integration/adapters/sneakers.rb:49:in `rescue in start_workers': Failed to start sneakers worker (RuntimeError)
	from /home/yahonda/src/github.com/rails/rails/activejob/test/support/integration/adapters/sneakers.rb:41:in `start_workers'
	from /home/yahonda/src/github.com/rails/rails/activejob/test/support/integration/helper.rb:27:in `<top (required)>'
	from /home/yahonda/src/github.com/rails/rails/activejob/test/helper.rb:12:in `require'
	from /home/yahonda/src/github.com/rails/rails/activejob/test/helper.rb:12:in `<top (required)>'
	from /home/yahonda/src/github.com/rails/rails/activejob/test/integration/queuing_test.rb:3:in `require'
	from /home/yahonda/src/github.com/rails/rails/activejob/test/integration/queuing_test.rb:3:in `<top (required)>'
	from /home/yahonda/.rbenv/versions/3.0.0-dev/lib/ruby/gems/3.0.0/gems/rake-13.0.1/lib/rake/rake_test_loader.rb:17:in `require'
	from /home/yahonda/.rbenv/versions/3.0.0-dev/lib/ruby/gems/3.0.0/gems/rake-13.0.1/lib/rake/rake_test_loader.rb:17:in `block in <main>'
	from /home/yahonda/.rbenv/versions/3.0.0-dev/lib/ruby/gems/3.0.0/gems/rake-13.0.1/lib/rake/rake_test_loader.rb:5:in `select'
	from /home/yahonda/.rbenv/versions/3.0.0-dev/lib/ruby/gems/3.0.0/gems/rake-13.0.1/lib/rake/rake_test_loader.rb:5:in `<main>'
/home/yahonda/src/github.com/rails/rails/activejob/test/support/integration/adapters/sneakers.rb:44:in `sleep': execution expired (Timeout::Error)
	from /home/yahonda/src/github.com/rails/rails/activejob/test/support/integration/adapters/sneakers.rb:44:in `block in start_workers'
	from /home/yahonda/.rbenv/versions/3.0.0-dev/lib/ruby/3.0.0/timeout.rb:112:in `timeout'
	from /home/yahonda/src/github.com/rails/rails/activejob/test/support/integration/adapters/sneakers.rb:42:in `start_workers'
	from /home/yahonda/src/github.com/rails/rails/activejob/test/support/integration/helper.rb:27:in `<top (required)>'
	from /home/yahonda/src/github.com/rails/rails/activejob/test/helper.rb:12:in `require'
	from /home/yahonda/src/github.com/rails/rails/activejob/test/helper.rb:12:in `<top (required)>'
	from /home/yahonda/src/github.com/rails/rails/activejob/test/integration/queuing_test.rb:3:in `require'
	from /home/yahonda/src/github.com/rails/rails/activejob/test/integration/queuing_test.rb:3:in `<top (required)>'
	from /home/yahonda/.rbenv/versions/3.0.0-dev/lib/ruby/gems/3.0.0/gems/rake-13.0.1/lib/rake/rake_test_loader.rb:17:in `require'
	from /home/yahonda/.rbenv/versions/3.0.0-dev/lib/ruby/gems/3.0.0/gems/rake-13.0.1/lib/rake/rake_test_loader.rb:17:in `block in <main>'
	from /home/yahonda/.rbenv/versions/3.0.0-dev/lib/ruby/gems/3.0.0/gems/rake-13.0.1/lib/rake/rake_test_loader.rb:5:in `select'
	from /home/yahonda/.rbenv/versions/3.0.0-dev/lib/ruby/gems/3.0.0/gems/rake-13.0.1/lib/rake/rake_test_loader.rb:5:in `<main>'
rake aborted!
Command failed with status (1): [ruby -w -I"lib:test" -I"/home/yahonda/.rbenv/versions/3.0.0-dev/lib/ruby/gems/3.0.0/gems/rake-13.0.1/lib" "/home/yahonda/.rbenv/versions/3.0.0-dev/lib/ruby/gems/3.0.0/gems/rake-13.0.1/lib/rake/rake_test_loader.rb" "test/integration/queuing_test.rb" ]
/home/yahonda/.rbenv/versions/3.0.0-dev/bin/bundle:23:in `load'
/home/yahonda/.rbenv/versions/3.0.0-dev/bin/bundle:23:in `<main>'
Tasks: TOP => test:integration:sneakers
(See full trace by running task with --trace)
$
```

- Result with this commit

```ruby
$ bundle exec rake test:integration:sneakers
... snip ...
15 runs, 6 assertions, 0 failures, 0 errors, 11 skips
```
2020-10-25 15:13:38 +09:00
Eugene Kenny 7cf8e30902 Work around getaddrinfo deadlock in forked process
See https://bugs.ruby-lang.org/issues/17220.

This will prevent every CI run from getting stuck and eventually timing
out after 30 minutes.
2020-10-16 01:00:12 +01:00
Akira Matsuda 09939f8657 Given method here (e.g. perform) should be public_sendable 2020-10-07 20:55:59 +09:00
George Claghorn 4cf7559280 Destroy associations in a background job.
Sometimes cascading association deletions can cause timeouts due to
an IO issue. Perhaps a model has associations that are destroyed on
deletion which in turn trigger other deletions and this can continue
down a complex tree. Along this tree you may also hit other IO
operations. Such deep deletions can lead to server timeouts while
awaiting completion and really the user may not notice all the
changes on their side immediately making them wait unnecesarially or
worse causing a timeout during the operation.

We now allow associations supporting the `dependent:` key to take `:destroy_async`,
which schedules a background job to destroy associations.

Co-authored-by: Adrianna Chang <adrianna.chang@shopify.com>
Co-authored-by: Rafael Mendonça França <rafael@franca.dev>
Co-authored-by: Cory Gwin @gwincr11 <gwincr11@github.com>
2020-09-24 14:24:15 -04:00
Akshay Birajdar b314ab555e Move require `active_support/core_ext/string/filters` to
`active_job/log_subscriber` from `active_job/logging`
2020-09-24 00:36:09 +05:30
fig 6a4e97c4bb fix typo in Active Job exceptions docs 2020-07-18 11:05:35 +01:00
Vipul A M 4432d471b8 Set timezone on a Job initialization to make it conform more with perform_later when doing JobClass.perform_now.
Fixes #39529
2020-06-04 09:53:42 +05:30
fatkodima 2156226e6e Do not swallow unknown configuration options for ActiveJob 2020-05-29 17:48:51 +03:00
Eugene Kenny 0ebc720a04 Set retry_jitter to 0.0 for upgraded applications
The point of new framework defaults is that they're opt-in for upgraded
applications, but the default for this option applied the new behaviour.
2020-05-27 22:15:19 +01:00
Jonathan Hefner b16c38ab6a Support procs for assert_{enqueued,performed}_with
PR #33995 added support for specifying the `args` argument of
`assert_enqueued_with` and `assert_performed_with` as a matcher proc.
In doing so, it added undocumented support for specifying the other
arguments as matcher procs as well.  This commit officially documents
that support, and adds tests to ensure the behavior.
2020-05-07 15:36:41 -05:00
Jonathan Hefner 7e08e19644 Fix assert_{enqueued,performed}_with doc examples [ci skip]
The example tests in the method docs for `assert_enqueued_with` and
`assert_performed_with` previously specified `queue` args in their
assertions but not in their setups.  Thus, the example tests would not
pass as written.  This commit fixes the examples, and properly
demonstrates the `queue` arg.
2020-05-07 14:13:10 -05:00
Rafael Mendonça França 684db54462
Add back the support to pass `at` as a proc in the job assertions 2020-05-01 12:22:57 -04:00
Santiago Bartesaghi 32bb46899d Remove unmaintained gem from README [ci skip] 2020-04-25 02:08:14 -03:00
Eugene Kenny 4c75e89a89
Merge pull request #38891 from jonathanhefner/fix-activejob-delay-test
Fix random CI fail due to cross-second time delay
2020-04-18 23:55:36 +01:00
Ryuta Kamizono 6f2126c760 Fixup CHANGELOGs [ci skip] 2020-04-15 21:23:24 +09:00
Étienne Barrié f123e5e40a Fix perform_enqueued_jobs without a block with other helpers
assert_enqueued_with with a block ignores all the jobs enqueued before
the block for its assertions by counting the number of jobs and dropping
the n first elements from the Array, but since we're now mutating the
Array in perform_enqueued_jobs without a block, it's broken.

This uses another implementation which is correct when the array is
mutated, by getting a duplicated array of jobs, then removing them from
the original array.

Similarly assert_enqueued_jobs with a block was using counts only, now
keeps track of the specific jobs to count them at the end.
2020-04-13 13:13:38 -04:00
Rafael Mendonça França 855c9897eb
Move CHANGELOG entry to the top 2020-04-08 17:22:38 -04:00
Rafael Mendonça França d16396e1ce
Merge pull request #38605 from dmitry/issue-38584
While using perform_enqueued_jobs enqueued jobs must be stored as well
2020-04-08 17:21:57 -04:00
Jonathan Hefner fa2584fc2b Fix random CI fail due to cross-second time delay
Example failure: https://buildkite.com/rails/rails/builds/68010#749ce70d-1e01-4419-90e5-ee4531f66466/1057-1069

Support for testing jobs with a relative time delay was added in #36767.
It was implemented by truncating the `usec` portion of the `at` time in
order to allow for sub-second time differences.  However, sub-second
time differences can occur across seconds.  Thus, this commit changes
`at` time matching to use an explicit time range.
2020-04-07 13:53:50 -05:00
Jonathan Hefner 056b252010 Fix random CI fail due to auto-updating timestamp
Example failure: https://buildkite.com/rails/rails/builds/68074#0fe7ca54-fcce-4a47-85db-a784275c8f51/1115-1125

Each time a job is serialized, `enqueued_at` is updated.  Thus, separate
serializations of the same job can have different `enqueued_at`
timestamps if the serializations do not occur within the same second.
2020-04-06 23:31:29 -05:00
Abhay Nikam bdfffd1355 Update the Rails mailing list URLs to new discuss discourse URL [ci skip] 2020-04-02 22:00:28 +05:30
Dino Maric df26d123f6 Sanitize and add missing docs on `ActiveJob::QueueAdapters` class. [ci skip]
I guess `NO` is pretty self-explanatory here. But, to be consistent, this commit
describes what does **NO** mean in the context of: `retries, timeaout and priorities`.
2020-03-22 11:28:03 +01:00
Rafael Mendonça França d9dc569d5b
Merge pull request #38749 from etiennebarrie/perform_enqueued_jobs_only_once
Perform enqueued jobs only once
2020-03-19 18:30:16 -04:00
dmitry 70fdc9e132 Move responsibility of the `filtered?` back to enqueue methods 2020-03-16 20:49:30 +01:00
Étienne Barrié c6d621d132 Remove jobs from queue when performing in tests
This makes sure jobs don't run twice if `perform_enqueued_jobs` is
called twice without a block.

This also mimics the behavior of using `perform_enqueued_jobs` with a
block, where at the end of the block performed jobs are not in
`enqueued_jobs` but instead in `performed_jobs`.
2020-03-16 15:09:33 -04:00
Étienne Barrié 78aa157d79 Add assertions to show test was mistaken 2020-03-16 14:09:34 -04:00
utilum 06dcc3c927 Fix warning: method redefined 2020-03-13 18:19:14 +01:00
Rafael França f0048109fc
Merge pull request #38676 from kwerle/correct_object_serializer_doc
Correct the parameter name for deserialize
2020-03-12 15:24:55 -04:00
Rafael França d2d8b2892d
Merge pull request #38702 from aditya-vector/activejob-jitter-documentation-update
Updates to ActiveJob::Exceptions.retry_on with jitter documentation [skip ci]
2020-03-11 13:43:19 -04:00
Aditya Narsapurkar 895c39fe96 Updates to ActiveJob::Exceptions.retry_on with jitter documentation [skip ci]
- Changelog updated
- Method documentation updated
2020-03-11 21:49:55 +05:30
Edouard CHIN 17e304def8 AJ `perform_enqueued_jobs` shouldn't perform job retries:
- ### Problem

  If we use `perform_enqueued_jobs` without a block, a job that
  uses a retry mechanism to reeenqueue itself would get performed
  right away.
  This behaviour make sense when using `perform_enqueued_jobs` with
  a block.

  However I'm expecting `perform_enqueued_jobs` without a block to
  perform jobs that are **already** in the queue not the ones that
  will get enqueued afterwards.

  ### Solution

  Dup the array of jobs given to avoid future mutation.
2020-03-09 19:46:11 -04:00
Edouard CHIN 13cb5b78a8 Fix AJ `TestAdapter#performed_jobs` not properly counting job:
- ### Problem

  If we use `perform_enqueued_jobs` without a block,
  a job that raises an error wouldn't be appended to
  the list of `performed_jobs`.

  ### Solution

  Push the job in the array before it is actually performed.
2020-03-09 19:46:11 -04:00
Kurt Werle 6852a53821 Correct the parameter name for deserialize
deserialize expects a JSON primitive
2020-03-07 11:48:48 -08:00
Aditya Narsapurkar 3aacd855cd parent 6d0895a489
author Aditya Narsapurkar <adityanarsapurkar@yahoo.com> 1582316102 +0530
committer Aditya Narsapurkar <adityanarsapurkar@yahoo.com> 1583159505 +0530

parent 6d0895a489
author Aditya Narsapurkar <adityanarsapurkar@yahoo.com> 1582316102 +0530
committer Aditya Narsapurkar <adityanarsapurkar@yahoo.com> 1583159327 +0530

Randomize jitter
- This PR attempts to fix a problem with ActiveJob jitter where the `determine_jitter_for_delay` value may not always be randomized. Especially when the jitter delay multplier is between 1 and 2 it always returns 0.
- With this change, we pass a range to `Kernel.rand` beginning with 0 to the `jitter_multiplier`. With positive float values, the return value will be a random float number from the range.
- Includes test cases to verify random wait time when the jitter_multiplier is between 1 and 2.
- Updated relevant test cases stubbing the `Kernel.rand` method, refactored some by removing unwanted stubs for `Kernel.rand` method where jitter is falsey.

Fixed rubocop issue - used assert_not_equal instead of refute_equal in test case

Fixed rubocop issue - used assert_not_equal instead of refute_equal in test case

Fixed rubocop issue - used assert_not_equal instead of refute_equal in test case

Review updates - separated test cases for random wait time with default and exponentially retrying jobs
- Another test case added to make sure negative wait time does not affect the randomization

Review updates
- Instead of using Kernel.rand with range, used simple multiplication with Kernel.rand for calculating delay for jitter
- Updates to the tests according to changes
2020-03-05 07:45:33 -08:00
Wojciech Wnętrzak d12a31b193
Add support for que name to Que adapter.
Co-authored-by: Brad Nauta <bradnauta@gmail.com>
2020-03-04 13:50:13 +01:00
Rafael França 40b7d93c5b
Merge pull request #38576 from Edouard-chin/ec-activejob-deprecation
Fix AJ wrong deprecation message on `after_callbacks_if_terminated`:
2020-03-03 15:28:50 -05:00
Edouard CHIN 0cdeee428e Fix AJ wrong deprecation message on `after_callbacks_if_terminated`:
- ### Problem

  In some cirumstances, the deprecation message to warn that AJ won't
  run `after_(enqueue/perform)` callbacks when the chain is halted
  by a `throw(:abort)` will be thrown even though no `throw(:abort)`
  was thrown.

  ```ruby
    run_callback(:foo) do
      ...
    end
  ```

  There is two possible way for the callback body to not be executed:

  1) `before` callback throw a `abort`
  2) `before` callback raises an error which is rescued by an
     around callback (See associated test in this commit for
     an example)

  When 2) happen we don't want to output a deprecation message,
  because what the message says isn't true and doesn't apply.

  ### Solution

  In order to differentiate between 1) and 2), I have added
  a `halted_callback_hook` which is called by ActiveSupport callback
  whenever the callback chain is halted.
2020-03-03 16:17:55 -04:00
Edouard CHIN 06dd162fb3 `ActiveSupport::Calbacks#halted_callback_hook` receive callback name:
- The `halted_callback_hook` method is called whenever the
  `terminator` halt the callback execution.
  Usually, this translate to when a `before` callback throw
  an `:abort`.

  <details>
    <summary> Example </summary>

    ```ruby
      class Foo
        include ActiveSupport::Callbacks

	define_callbacks :save
	set_callback(:save, :before) { throw(:abort) }

	def run
	  run_callbacks(:save) do
	    'hello'
	  end
	end

	def halted_callback_hook(filter)
	  # filter is the proc passed to `set_callback` above
	end
      end
    ```
  </details>

  ### Problem

  When a class has multiple callbacks, (i.e. `save`, `validate` ...),
  it's impossible to tell in the halted_callback_hook which type of
  callback halted the execution.
  This is useful to take different action based on the callback.

  <details>
    <summary> Use Case </summary>

    ```ruby
      class Foo
        include ActiveSupport::Callbacks

	define_callbacks :save
	define_callbacks :validate

	set_callback(:save, :before) { throw(:abort) }
	set_callback(:validate, :before) { throw(:abort) }

	def run
	  run_callbacks(:validate) do
	    ...
	  end

	  run_callbacks(:save) do
	    ...
	  end
	end

	def halted_callback_hook(filter)
	  Rails.logger.warn("Couldn't save the record, the ??? callback halted the execution")
	end
      end
    ```
  </details>

  ### Solution

  Allow `halted_callback_hook` to receive a second argument which is
  the name of the callback being run.
2020-03-03 16:17:55 -04:00
dmitry 7e6e6eb56f While using perform_enqueued_jobs enqueued jobs must be stored as well #38584 2020-02-28 13:32:06 +01:00
Ryuta Kamizono 1d3eb7be13 Fixup CHANGELOGs [ci skip] 2020-02-25 14:14:54 +09:00
Edouard CHIN d35cf4c05d Fix ActiveJob Test adapter not respecting retry attempts:
- ### Problem

  Given the below example the test adapter will retry the job
  indefinitely:

  ```ruby
    class BuggyJob < ActiveJob::Base
      retry_on(Exception,  attempts: 2)

      def perform
        raise "error"
      end
    end

    BuggyJob.perform_later
    perform_enqueued_jobs
  ```

  The problem is that when the job get retried, the
  `exception_executions` variable is not serialized/deserialized,
  resulting in ActiveJob to not be able to determine how many time
  this job was retried.

  The solution in this PR is to deserialize the whole job in the test
  adapter, and reserialize it before retrying.

  Fix #38391
2020-02-10 17:59:20 -04:00
Ryuta Kamizono 8e452c710d Fix keyword arguments warnings in Action Mailer 2020-01-21 09:23:15 +09:00
Ryuta Kamizono fc67857596 Fix keyword arguments warnings in Active Job
Related #38053, #38187, #38105, #38260.

This is a reattempt to fix keyword arguments warnings in Active Job.

Now Ruby (master) has `Hash.ruby2_keywords_hash{?,}` and that will be
backported to 2.7.1.

https://github.com/ruby/ruby/pull/2818
https://bugs.ruby-lang.org/issues/16486

I've emulated that for 2.7.0 and older versions.
2020-01-21 05:53:23 +09:00
Ryuta Kamizono 99f18b618b Revert "Merge pull request #38260 from kamipo/fix_kwargs_warning_for_activejob"
This reverts commit 80e72c5eb7, reversing
changes made to 0dad1e3e77.
2020-01-21 05:26:44 +09:00
Ryuta Kamizono 950b39482d Fix keyword arguments warnings in Active Job
Related #38053, #38187, #38105.

This is a reattempt to fix keyword arguments warnings in Active Job.

Now Ruby (master) has `Hash.ruby2_keywords_hash{?,}` and that will be
backported to 2.7.1.

https://github.com/ruby/ruby/pull/2818
https://bugs.ruby-lang.org/issues/16486

I've emulated that for 2.7.0 and older versions.
2020-01-19 12:09:54 +09:00
Douglas Lara 10803d6985 fix typos 2020-01-15 00:11:40 -03:00
Rafael Mendonça França a901372e61
Revert "Merge pull request #38053 from Shopify/actionmailer-6-0-stable-ruby-2.7-warnings"
This reverts commit 59e4c996b3.

Closes #38187.
2020-01-08 12:01:02 -03:00
Edouard CHIN ca61139fae Fix wrong logging message in AJ in case a job returns a falsey value:
- I made a change in 0d3aec4969 to output a log if a job was aborted
  in a before callbacks. I didn't take in consideration that a job
  could return a falsy value and thus it would wrongly log
  that the job was aborted.

  This fixes the problem by checking if the callback chain was halted
  rather than the return value of the job.
2020-01-03 17:14:56 +01:00
Edouard CHIN 2cd05dda2b Fix regression where AJ#perform_now doesn't return the job's value:
- Fix #38040
2020-01-03 17:14:56 +01:00
Abhay Nikam d8beb77252 Bump license years from 2019 to 2020 [ci skip] 2020-01-01 15:10:31 +05:30
Edouard CHIN be60970be7 Set AJ `return_false_on_aborted_enqueue` true in the test suite:
- Since this is going to be the default in 6.1, let's set it in the
  test suite to avoid deprecation warning.
  Otherwise one has to do `AS::Deprecation.silence { }` everytime we
  add a new test.

  Fix #38107
2019-12-28 16:56:54 +01:00
Ryuta Kamizono 59e4c996b3 Merge pull request #38053 from Shopify/actionmailer-6-0-stable-ruby-2.7-warnings
Fix Ruby 2.7 warnings in Action Mailer 6.0
2019-12-20 22:40:31 +09:00
Rafael França 3c7c2d220e
Merge pull request #37994 from bibstha/remove_activejob_logging_backtrace
Remove stacktrace from ActiveJob logging callback halts
2019-12-19 12:27:22 -03:00
Cliff Pruitt db0bc5e6d5 Disable ActiveJob retry jitter when given zero/falsey value (#38003)
* Add failing ActiveJob exceptions test for "disable retry jitter"

Thanks to @kaspth for the starting point.

* Update ActiveJob retry jitter to correctly use zero value

* Simplify "disable retry jitter" test

We don't need to repeat this many times. Fewer is shorter.

* Refactor determine_delay with jitter

* Fix indentation

* Close the curtains and give JITTER_DEFAULT some privacy

* Use .zero? instead of == to check jitter value

* Add ActiveJob test for explicit zero jitter

Co-authored-by: Kasper Timm Hansen <hey@kaspth.com>
Co-authored-by: Cliff Pruitt <cliff.pruitt@cliffpruitt.com>
2019-12-17 15:23:52 -03:00
Bibek Shrestha 210bf6aa39 Remove stacktrace from ActiveJob logging callback halts
ActiveJob will log the entire backtrace when one of the enqueue
callbacks fail. This is not necessary and increases noise. When there is
an Exception object, the object gets bubbled up eventually anyways.

Remove `Array(ex.backtrace).join("\n")` from `def enqueue` and `def
enqueue_at`.
2019-12-16 18:46:04 -05:00
Kasper Timm Hansen a8cbb96b3d
make that a private instance method instead 2019-12-15 03:46:02 +01:00
Kasper Timm Hansen d258bfe8ac
Consolidate and give context to `after` callback deprecation
The existing message only mentioned one type of before/after callback,
but the config was named generally. That mismatch is confusing and users
wouldn't necessarily know what the total effect of the config would be.

So instead of handwriting the deprecation warning in the specific instances,
consolidate it in one place and give the appropriate context. That context
is the above, but also that users shouldn't update their app config,
they should uncomment the line in the new defaults file, which now also
has more context.

I'm not totally convinced that we can't move this to when
`after_enqueue`/`after_perform` is called in the job class. Doesn't
seem worth it to blare this after every job enqueue/perform, when we
the score at boot time.

cc @Edouard-chin
2019-12-15 03:20:07 +01:00
Edouard CHIN 9eb4b4ed01 Fix deprecation being thrown at boot time:
-
  ### Problem

  In rails/rails@bbfab0b33a I introduced a change which outputs
  a deprecation whenever a class inherits from ActiveJob::Base.

  This has the negative effect to trigger a massive amount of
  deprecation at boot time especially if your app is eagerloaded
  (like it's usually the case on CI).

  Another issue with this approach was that the deprecation will
  be output no matter if a job define a `after_perform` callbacks
  i.e.
  ```ruby
    class MyJob < AJ::Base
      before_enqueue { throw(:abort) }
    end

    # This shouldn't trigger a deprecation since no after callbacks are defined
    # The change in 6.2 will be already safe for the app.
  ```

  ### Solution

  Trigger the deprecation only when a job is abort
  (during enqueuing or performing) AND a `after_perform`
  callback is defined on the job.
2019-12-13 03:25:03 +01:00
Kasper Timm Hansen ff299f1741
Set default directly with default: 2019-12-13 02:09:08 +01:00
Kasper Timm Hansen 5ded839cfb
Strip default_ prefix from retry_jitter config to match conventions 2019-12-13 01:42:58 +01:00
Cliff Pruitt e2cdffce3d Add config option for ActiveJob::Base.default_retry_jitter 2019-12-10 12:11:46 -05:00
Edouard CHIN bbfab0b33a Don't run AJ after_enqueue / after_perform when chain is halted:
- ### Problem

  ```ruby
    MyJob < ApplicationJob
      before_enqueue { throw(:abort) }
      after_enqueue { # enters here }
    end
  ```
  I find AJ behaviour on after_enqueue and after_perform callbacks
  weird as they get run even when the callback chain is halted.
  It's counter intuitive to run the after_enqueue callbacks even
  though the job wasn't event enqueued.

  ### Solution

  In Rails 6.2, I propose to make the new behaviour the default
  and stop running after callbacks when the chain is halted.
  For application that wants this behaviour now or in 6.1
  they can do so by adding the `config.active_job.skip_after_callbacks_if_terminated = true`
  in their configuration file.
2019-12-09 17:17:23 +01:00
Edouard CHIN 0d3aec4969 Fix ActiveJob logging when callback chain is halted:
- ### Problem

  ActiveJob will always log "Enqueued MyJob (Job ID) ..." even
  if the job doesn't get enqueued through the adapter.
  Same problem happens when performing a Job, "Performed MyJob (Job ID) ..." will be logged even when job wasn't performed at all.
  This situation can happen either if the callback chain is terminated
  (before_enqueue throwing an `abort`) or if an exception is raised.

  ### Solution

  Check if the callback chain is aborted/exception is raised, and  log accordingly.
2019-12-09 16:17:55 +01:00
T.J. Schuck fa429f9a51 Small doc fixes for ActiveJob::Exceptions::ClassMethods#retry_on
Follow up to https://github.com/rails/rails/pull/31872

Particularly, the closing `</tt>` tag of the documented wait algorithm had a misplaced `<`.  Threw in a space between `15% (0.15)` for good measure.

[ci skip]
2019-12-04 16:27:41 -05:00
Anthony Ross 5f7621878d Add jitter to :exponentially_longer
Prior to this change, exponentially_longer had adverse consequences
during system-wide downstream failures.  This change adds a random value to the
back off calculation in order to prevent the thundering herd
problem, whereby all retry jobs would retry at the same time.

Specifically this change adds a jitter option to retry_on to enable users of it to
scope the randomness calculation to a reasonable amount.  The default is
15% of the exponential back off calculation.
2019-11-27 16:03:11 -08:00
Ryuta Kamizono 214f439343 Fixup CHANGELOGs [ci skip] 2019-11-24 09:20:00 +09:00
lrns d6a7aab4fd Fix small typo in activejob changelog 2019-11-09 15:13:07 +01:00
Rafael Mendonça França ce085f62d4
Add an option to disable logging for jobs with sensitive arguments
class SensitiveJob < ApplicationJob
      self.log_arguments = false

      def perform(my_sensitive_argument)
      end
    end

When dealing with sensitive arugments as password and tokens it is
now possible to configure the job to not put the sensitive argument
in the logs.

Closes #34438.
2019-11-08 13:53:23 -05:00