Commit Graph

391 Commits

Author SHA1 Message Date
Rafael Mendonça França
53a3a95d01
Merge PR #48010 2023-08-21 17:39:03 +00:00
Jonathan del Strother
074d431493
Fix invalid durations in ActiveJob serialization
Durations that were round-tripped through ActiveJob::Arguments.serialize
would appear fine at a first glance, but trying to perform
duration-math on them would fail:

```
irb(main):001:0> d = ActiveJob::Arguments.deserialize(ActiveJob::Arguments.serialize([1.year]))[0]
=> 1 year
irb(main):002:0> d + 1.day
activesupport-6.1.4.4/lib/active_support/duration.rb:242:in `+': undefined method `merge' for [[:years, 1]]:Array (NoMethodError)
```
2023-08-13 11:27:16 +01:00
Yasuo Honda
d867313fbc
Merge pull request #48626 from ghiculescu/active-job-async-test
Active Job: `async` adapter should always run jobs immediately if `immediate` set
2023-07-03 09:37:56 +09:00
Alex Ghiculescu
639dab59dc Active Job: async adapter should always run jobs immediately if immediate set
This is an internal fix, not user facing. I noticed it while working on https://github.com/rails/rails/pull/48585.

The `async` adapter has an `immediate` option, which should only be used in tests. This option should tell the adapter to run jobs inline. This works correctly with `perform_later`, but it does not work with `enqueue_at`, which is what other internal mechanisms such as `retry_job` use.

This PR fixes this bug.
2023-07-03 09:02:51 +10:00
Alex Ghiculescu
2385b6e4e5 Fix incorrect arguments for Active Job test job
This is an internal fix, not user facing.

Currently the `LoggingJob` does not accept more than one argument. But there's [a few tests](f46d3452ae/activejob/test/cases/test_helper_test.rb (L518-L537)) that call it with multiple arguments and assert that it is queued correctly. Those tests pass because the job is not performed, but if the job was performed, they'd fail.

This PR just fixes `LoggingJob` to accept a splat of arguments, and adds a test to ensure that it works correctly.
2023-07-02 16:25:09 +10:00
Alex Ghiculescu
ba70a5be86 Make perform_enqueued_jobs compatible with all Active Job adapters 2023-06-28 20:08:08 +10:00
Alex Baldwin
719e49485f Fix error ActiveJob passed class with permitted?
Resolves #48561
Co-authored-by: Sampat Badhe <sampatbadhe@gmail.com>
2023-06-23 10:51:46 -04:00
Alex
10bb51a123 Update Active Job testing guide
The testing guide for Active Job currently implies that when you queue a job it will be performed.

This isn't true; by default jobs are enqueued, not performed.

This PR fleshes out the docs a bit to show both examples, and adds a test to confirm the default behaviour.
2023-06-20 09:58:33 +10:00
Rob Cardy
659d41110f
This method lets job authors define a block which will be run when a job is about to be discarded.
This has utility for gems/modules included on jobs, which can tie into this behaviour and run something when a job fails.
after_discard respects the existing retry behaviour, but will run even if a retried exception is handled in a block.
2023-05-08 14:28:42 -04:00
Yasuo Honda
0b5f6ad82f
Merge pull request #48157 from shivamsinghchahar/improve-aj-queue-adapter-test
Improve AJ queue adapter test case
2023-05-08 11:44:12 +09:00
Shivam Chahar
daf6e2b0de Improve AJ queue adapter test case
In this test case we only check if the third child's queue adpter is nil or not. We should instead check if the queue adapter is the same as base adapter to ensure that it did not change when we changed qdapters for other jobs.
50f0c0f064/activejob/test/cases/queue_adapter_test.rb (L44-L52)
2023-05-07 12:44:53 +05:30
Shivam Chahar
8ccf129ea1 Fix typo in activejob tests
changes `know` -> `known` in activejob serializers test
2023-05-03 20:38:48 +05:30
Shivam Chahar
17d1b83b07 Add tests for AJ to verify queue name passed as symbol. Ref: #48034 2023-04-26 21:37:00 +05:30
Sander Verdonschot
6daba18791
Allow queue adapters to provide a custom name
This gives queue adapters more freedom to name and organize their code.

For example, if `FancyQueue` wants to have their adapter at
`FancyQueue::ActiveJobAdapter`, the name would be `active_job` before this
change. After this change, they can implement `queue_adapter_name` to return
`fancy_queue`.
2023-04-20 13:23:50 -04:00
Sander Verdonschot
6b4acb57e2
Fix name extraction for module queue adapters
Before this change, setting a module as queue adapter would result in
`queue_adapter_name` being `"module"`. This PR fixes the name extraction logic
to handle module or class queue adapters.
2023-04-19 18:51:49 -04:00
fatkodima
5ab2034730 [ActiveJob] Add logging for enqueue_all 2023-04-04 13:18:19 +03:00
fatkodima
f6d56fed27 Add support for logging background job enqueue callers 2023-04-02 03:23:42 +03:00
Pascal Zumkehr
3d3ed6eeb0 Make delayed job display_name failsafe
The display_name method is used by delayed job to log information
about a certain job, including failure messages. Whenever a job class
is moved or deleted, the instances still scheduled cannot be
constantized anymore, causing display_name and hence the log method to
raise an exception. In certain cases, e.g. when logging happens in a
rescue block, this may terminate the entire delayed job worker. With
the failsafe method, the worker handles failed jobs gracefully and
continues work, all with appropriate log output.
2023-03-02 13:38:38 +01:00
Sander Verdonschot
9b62f88a2f
Add perform_all_later to enqueue multiple jobs at once
Sidekiq has a useful optimisation called `push_bulk` that enqueues many jobs at
once, eliminating the repeated Redis roundtrips. However, this feature is not
exposed through Active Job, so it only works for `Sidekiq::Worker` jobs. This
adds a barrier to Active Job adoption for apps that rely on this feature. It
also makes it harder for other queue adapters to implement similar
functionality, as they then have to take care of serialization, callbacks, etc.
themselves.

This commit adds `ActiveJob.perform_all_later(<job1>, <job2>)`, backed by
Sidekiq's `push_bulk` and with a fallback to enqueuing serially if the queue
adapter does not support bulk enqueue.

The performance benefit for 1000 jobs can be more than an order of magnitude:

| Enqueue type       | Serial time (ms) | Bulk time (ms) | Speedup |
| ------------------ | ---------------- | -------------- | ------- |
| Raw Sidekiq        |             2661 |            119 |     22x |
| Active Job Sidekiq |             2853 |            208 |     14x |

(Measured in a simple test app in our production environment.)

Instrumentation for perform_all_later uses a new event `enqueue_all.active_job`
2023-02-02 16:39:22 -05:00
Hartley McGuire
285b63acd9
Fix compatability between tests and Sidekiq 6.5
Since Sidekiq 7.0 requires Ruby 2.7, older versions of Rails that
support older Rubies are still tested against Sidekiq 6.x.

Sidekiq::MAJOR was added in 7.0 so it can't be used for version testing,
see 862dc5b

The config change is due to changes in Sidekiq 6.5. These were accounted
for in 7a069dc but removed in 6d31993.
2023-01-08 20:41:59 -05:00
Hartley McGuire
862dc5b9ca
Fix activejob integration for Sidekiq 6
Sidekiq::MAJOR was added in mperham/sidekiq@b4092e3, which is only
included in 7.0.0+ so we can't use it to check the version for
Sidekiq 6.

Since the test code is written to support both, the condition should
also support both.
2023-01-07 13:45:15 -05:00
Jonathan Hefner
77db302aa0 Add ActiveJob.deprecator
This commit adds `ActiveJob.deprecator` and replaces all usages of
`ActiveSupport::Deprecation.warn` in `activejob/lib` with
`ActiveJob.deprecator`.

Additionally, this commit adds `ActiveJob.deprecator` to
`Rails.application.deprecators` so that it can be configured via
settings such as `config.active_support.report_deprecations`.

This commit also removes a defunct `ActiveSupport::Deprecation.silence`
call that was added in 9eb4b4ed01f893c2fc7ff3ee4f99301dec7ea3c2 but not
removed when the deprecation was completed in
10bd5e59c3291bb2034869e97cca30634a559afb.
2022-10-31 17:04:26 -05:00
fatkodima
6d31993664 Fix running ActiveJob tests for sidekiq 7.0 2022-10-28 20:36:13 +03:00
Ariel Valentin
658fd53741
fix: Ensure ActiveJob::TestHelper sets scheduled_at to a Float
I noticed a difference in behavior when inspecting `ActiveJob::Core#scheduled_at` in non-test environments vs when inspecting in while executing tests.

Prior to this change, `ActiveJob::TestHelper` would set `ActiveJob::Core#scheduled_at` to a `Time` object in tests,
however this attribute was set to a `Float` objects in non-test environments:

<d1aa6af5cc/activejob/lib/active_job/core.rb (L161)>

This change ensures parity in all runtime environments.
2022-10-17 19:22:24 +00:00
Jean Boussier
d917896f45 Enable verbose mode in test and report warnings as errors
We recently let a few very easy to avoid warnings get merged.
The root cause is that locally the test suite doesn't run in
verbose mode unless you explictly pass `-w`.

On CI warnings are enabled, but there is no reason to look at the
build output unless something is failing. And even if one wanted
to do that, that would be particularly work intensive since warnings
may be specific to a Ruby version etc.

Because of this I believe we should:

  - Always run the test suite with warnings enabled.
  - Raise an error if a warning is unexpected.

We've been using this pattern for a long time at Shopify both in private
and public repositories.
2022-10-11 09:25:18 +02:00
Yasuo Honda
cb22eb2b36 Remove QueAdapter from Active Job
Que and Rails (Active Job QueAdapter) have applied changes each other
to support Ruby 3 keyword arguments and options provided as top level keywords, etc
via these commits:

https://github.com/rails/rails/pull/44734
https://github.com/rails/rails/pull/44248
d9244b9074 via https://github.com/que-rb/que/pull/319

Finally, we've found it is quite difficult to maintain them.
Going forward Active Job Que adapter can be included in the future version of que gem itself.
Refer to https://github.com/rails/rails/issues/45899 the background for this change.

Active Job Que adapter can be included in the future version of que gem itself.
2022-09-12 22:31:10 +09:00
Jean Boussier
545482650b Update redis and resque
Fix: https://github.com/rails/rails/issues/45913
2022-09-07 15:10:43 +02:00
Sam Bostock
bc1f323338
Add ActiveJob::Serializers::BigDecimalSerializer
Previously, BigDecimal was listed as not needing a serializer.  However,
when used with an adapter storing the job arguments as JSON, it would get
serialized as a simple String, resulting in deserialization also producing
a String (instead of a BigDecimal).

By using a serializer, we ensure the round trip is safe.

During upgrade deployments of applications with multiple replicas making use of
BigDecimal job arguments with a queue adapter serializing to JSON, there exists
a possible race condition, whereby a "new" replica enqueues a job with an
argument serialized using `BigDecimalSerializer`, and an "old" replica fails to
deserialize it (as it does not have `BigDecimalSerializer`).

Therefore, to ensure safe upgrades, serialization will not use
`BigDecimalSerializer` until `config.active_job.use_big_decimal_serializer` is
enabled, which can be done safely after successful deployment of Rails 7.1.

This option will be removed in Rails 7.2, when it will become the default.
2022-07-19 15:31:41 -04:00
Sam Bostock
eb4b540368
Clear JobBuffer on teardown
ActiveJob tests should be able to rely on a clean JobBuffer in each test.
2022-07-18 23:33:07 -04:00
Jeremy Daer
8d9d8013ca Preserve job.enqueued_at timestamp precision
* Allows instrumenters to more accurately deduce queue wait time
* Retains IS08601 compatibility

References #39698
2022-07-12 18:13:16 -07:00
Juanito Fatas
7a069dc6f8 Work around Sidekiq 6.4 and 6.5 API difference 2022-06-10 00:47:09 +09:00
Juanito Fatas
6e6e2b9457 Prepare for upcoming Sidekiq Configuration design
Reference commit: 67daa7a408

While the docs[1] suggests to use Sidekiq::Config, but it is not
available yet. So uses Sidekiq instead to make activejob integration
tests work.

[1]https://github.com/mperham/sidekiq/blob/main/docs/global_to_local.md#explicit-configuration
2022-06-10 00:16:35 +09:00
Andrew White
fca1aeed9c
Allow overriding of Que and QC urls in integration tests
The Active Job integration tests for Que and Queue Classic assume a
connection to a PostgreSQL database running on localhost:5432 since the
psql command to create the databases does not pass the -h and -p options.
2022-03-19 10:19:23 +00:00
Matthew Draper
e28c4e5d59 Add missing requires 2022-02-17 11:13:51 +10:30
Jonathan Rochkind
dcce260edc Add job_id and exception message to ActiveJob retry/discard logging
In other log messages like perform/performed and ActiveJob error logging, the job ID and exception message were already included, eg:

    Error performing TestFailureJob (Job ID: d70ad13e-e58b-409c-a8cc-e0447fc792b5) from Resque(default) in 1446.56ms: RuntimeError (Error Message):

But log message related to retry/discard behavior from ActiveJob::Exceptions did not include the Job ID or exception message. We now include them, in a consistent format with other existing messages.

Job ID is especially useful because, while other ActiveJob-related log messages get the Job ID via tagged logging, retry-related log messages do not currently end up tagged with Job ID. And it's really useful to use Job ID to be able to collect all the log lines related to a particular job, put the error messages together with the retry and subsequent perform messages.

We also include job.executions in the enqueue_retry log message because it was available and useful, to know if this is the 1st retry or 2nd or whatever. Previously job.executions was included in retry_stopped logging, but not enqueue_retry.
2022-02-08 10:06:21 -05:00
Hartley McGuire
f83f5c81af fix Que integration tests for Active Job
Replace Que.* settings that were removed in Que 1.0 with options passed
to Que::Locker. The Locker class creates its own thread for managing
work distribution, so the Thread created in the QueJobsManager was also
removed.
2022-01-27 16:24:16 -05:00
Hartley McGuire
b6b2001f51 add assertion helpers for Active Job integration
Using `assert` by itself without an error message leads to test output
like the following:

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

These added helpers provide a more specific error message so that the
reasons for test failures become more clear:

```
Failure:
QueuingTest#test_current_timezone_is_kept_while_running_perform_later [.../rails/activejob/test/integration/queuing_test.rb:118]:
Job AJ-63fe8bf6-7062-4a56-a10a-97c37fcaa6e6 was not executed
```
2022-01-26 19:41:45 -05:00
Hartley McGuire
4eefa1feb0 fix que integration in Active Job tests part 2
Fixing the synchronous setting uncovered some more errors with Que 1.0:
exception tests with retry_on started failing due to an assertion in
Que's Active Job integration that running jobs won't nest. However, this
is not the case when running retriable jobs synchronously.

This change overrides Que's Active Job wrapper to not make this
assertion.

I also opened an issue in the que repo: https://github.com/que-rb/que/issues/329
2022-01-24 21:56:38 -05:00
Hartley McGuire
ee5d18bb92 fix que integration in Active Job tests
Que.mode was removed in 6783fdd68a
and replaced by Que.run_synchronously = true per changelog:
fa4988ee33/CHANGELOG.md (L120)

It looks like it started failing because Que 1.0 was released yesterday.
2022-01-24 16:15:22 -05:00
Rafael Mendonça França
6fb54c00e4
Merge PR #43066 2022-01-06 16:53:31 +00:00
Rafael Mendonça França
10bd5e59c3
Removed deprecated behavior that was not halting after_enqueue/after_perform callbacks when a previous callback was halted with throw :abort. 2021-11-17 21:51:17 +00:00
Dorian Marié
13b3c46365 fix typo of using where instead of were 2021-11-07 14:17:00 +01:00
HParker
29e502f374 Improve active_job test_helper error messages
Error messages from assert_enqueued_with and assert_performed_with
shows which other jobs are enqueued or performed when you get an
error.  We can improve these messages to make it clearer why the job
didn't match. This one error messages now have three different formats
based on why the job didn't match

1. Didn't match because no jobs are queued at all. This now reports,
```
No performed job found with {:job=>HelloJob, :args=>[]}

No jobs where performed
```

2. Didn't match because that job class was not queued. This now reports,
```
No performed job found with {:job=>MultipleKwargsJob, :args=>[#<Person:0x00007fe38f9f8100 @id=11>]}

No jobs of class MultipleKwargsJob where performed, job classes performed: HelloJob
```

3. Doesn't match due to arguments, queue, priority or other reason. This now reports
```
No performed job found with {:job=>HelloJob, :args=>[#<Person:0x00007fe3a89fc2c8 @id=11>]}

Potential matches: {"job_class"=>"HelloJob", "job_id"=>"f8636fd9-c7a0-4565-9198-17e175f30f0e", "provider_job_id"=>nil, "queue_name"=>"default", "priority"=>nil, "arguments"=>[{"_aj_globalid"=>"gid://aj/Person/9"}], "executions"=>0, "exception_executions"=>{}, "locale"=>"en", "timezone"=>nil, "enqueued_at"=>"2021-10-27T23:19:54Z", :job=>HelloJob, :args=>[#<Person:0x00007fe3a89dce00 @id="9">], :queue=>"default", :priority=>nil}
```

Which matches the old error message, but only reports jobs that where
queued of the same class as the job you are asserting was queued.
2021-10-27 16:31:50 -07:00
Veerpal Brar
0f259e702d Raise error when serializing an anonymous class.
The ModuleSerializer does not support serializing anonymous classes
because when we try to deserialize the anonymous class, it wouldn't
know which class to use (since class name is nil).

For this reason, ModuleSerialzier now raises an error if the class
name is nil. Previously, ModuleSerializer would raise an `undefined
method `constantize' for nil:NilClass` error during deserialization.
It's not clear why the deserialization failed from the error.

In this commit, we raise an explicit error when trying to serialize
an anonymous class indicating this behaviour is not supported.
2021-10-13 11:55:23 -04:00
Ben Sheldon
c4fcb4e6ee Allow ActiveJob::Base.set to configure job when using .perform_now 2021-10-12 13:53:38 -07:00
Jean Boussier
c91c266872 Enable Style/ExplicitBlockArgument cop
This reduce the stack size which is beneficial for
exceptions performance.

See: https://gist.github.com/byroot/cb3bcadcc3701c2518d002fb8d3a4e7a

However the cop is unsafe because it might change the block arity,
so it can run into some false positives.
2021-09-05 17:06:19 +02:00
Jacopo
20545fc820 Allow testing discard_on/retry_on ActiveJob::DeserializationError
Previously in `perform_enqueued_jobs`, `deserialize_arguments_if_needed`
was called before calling `perform_now`. When a record no longer exists
and is serialized using GlobalID this led to raising
an `ActiveJob::DeserializationError` before reaching `perform_now` call.
This behaviour makes difficult testing the job `discard_on/retry_on` logic.

Now `deserialize_arguments_if_needed` call is postponed to when `perform_now`
is called.

Example:

```ruby
class UpdateUserJob < ActiveJob::Base
  discard_on ActiveJob::DeserializationError

  def perform(user)
    # ...
  end
end

User.destroy_all
assert_nothing_raised do
  perform_enqueued_jobs only: UpdateUserJob
end
assert_no_enqueued_jobs
```

Before this changes the test will fail, now it passes.
2021-08-23 21:16:56 +02:00
Xavier Noria
324883dc50 Delete extra empty line 2021-08-22 01:28:14 +02:00
Xavier Noria
7c09e59bca Restore AJ autoloading test
This commit restores the test deleted in

    cd22ecbfc2

Active Job should not test things about autoloading, this would
belong to the railties test suite probably. However, there, it feels
a bit too distant from here.

Imperfect, but on a second thought I believe this trade-off is better.
2021-08-22 01:23:14 +02:00
Koichi ITO
65af100ddd Tweak unreachable assertion tests in the block of assert_raises
I found an unexpected use of assertion in the block of `assert_raise`
when I implemented https://github.com/rubocop/rubocop-minitest/pull/137.
It is expected to be asserted after an exception is raised in
`assert_raise` block, but in actually it is not asserted after an
exception is raised. Therefore, this PR removes or updates assertions
that have not been asserted after an exception has raised.

This PR will add `rubocop-minitest` and enable
`Minitest/UnreachableAssertion` cop to able similar auto-detection,
but will remove `rubocop-minitest` from this PR if you don't like it.
2021-08-17 20:33:08 +09:00