New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add failing spec for issue #2299 #2301
Conversation
I guess it boils down to: t = Time.current
t == Time.at(t.to_f) We do I suspect that it's ActiveJob serialization that is responsible for Do you have an idea of how to work around that comparison issue? |
Event without t = Time.current
t == Time.at(t)
# => false You could compare t = Time.current
t.to_f == Time.at(t).to_f
# => true |
At the same time: t = Time.now
t == Time.at(t) # => true So I guess it's something Rails-related. Do you think it's possible to work this around, would you be up to fixing this issue? |
It's about nanosecond precision it seems and # Time.now isn't that precise
t = Time.now
t.nsec # => 81297000
Time.at(nsec) # => 81297000
# Neither is Time.current
t = Time.current
t.nsec # => 678132000
Time.at(t).nsec # => 678132057
Time.at(t).nsec # => 678132057
Time.at(t).nsec # => 678132057
# WAT |
Hmm for me timezone gets really weird, too: t = Time.current
t
# => Thu, 26 Mar 2020 15:10:32 CET +01:00
Time.at(t)
# => 2020-03-26 15:10:32 3221285/4194304 +0100
Time.at(t.utc)
# => 2020-03-26 14:11:45.30499 UTC
# comparing with utc works??
t == Time.at(t.utc)
# => true |
Nice catch! |
Unfortunately not:
|
Ooops, sorry for the confusion, not that |
Hehe np, I tried this too already, but same error:
I also tried different other variations, no luck, spec fails: values_match?(@at.utc, Time.at(job[:at]))
values_match?(@at.utc, Time.at(job[:at]).utc)
values_match?(@at, Time.at(job[:at]).utc) |
How about values_match?(Time.at(@at), Time.at(job[:at])) |
Nope, still
I tried some more variations, all fail: values_match?(Time.at(@at).utc, Time.at(job[:at]).utc)
values_match?(Time.at(@at.utc), Time.at(job[:at]).utc)
values_match?(Time.at(@at.utc), Time.at(job[:at])) This one works though: values_match?(@at.to_datetime, Time.at(job[:at]).to_datetime) ... but kills other specs, for example ...
|
I feel this is an issue with job serialisation, we need to ensure we are serialising arguments the same as action job is, and then compare them. |
I've managed to work around the rounding problem like that: @at = Time.at(@at.to_f) if Time === @at
values_match?(@at, Time.at(job[:at])) I believe |
I mean rather than reimplementing it, we should be delegating to Rails |
Do we know why it broke with 4.0?
Maybe it could be reverted so it will work again. And then what is the real problem with 4.0 right now?
|
Sorry, I probably don't quite understand what you mean. I don't see a clear way to pass our expected values to Rails for further comparison, due to argument matchers that can be used instead of the real values (e.g. regexp for a have_enqueued_job(hello_job).with { |arg|
expect(arg).to eq("zxcv")
} |
Rails is rounding expected
This is something we should reuse or mimic. This rounds it to the whole seconds though: t.change(usec: 0).nsec # => 0 They also do that for the other side of the equation:
We probably don't need that. |
We changed the matchers significantly in 4.0 for various enhancements and bug fixes. I haven't had time to bisect it but you could with this spec.
I'm going to say no because of the scope of the changes but you could just use 3.9 if that worked for you until its fixed? Or help fix it for a
@pirj Jobs are serialised, we should serialise/deserialise arguments where appropriate. |
I git bisect and found a commit: b1e27e2 It was related to #2205 The repo I used with the spec file: https://github.com/benoittgt/testing_6_0_0_rc1/blob/active-job-time-error/spec/jobs/guests_cleanup_job_spec.rb require 'rails_helper'
RSpec.describe GuestsCleanupJob, type: :job do
before do
ActiveJob::Base.queue_adapter = :test
end
it 'enque the job' do
date = Time.current.utc.change(usec: 0) + 1.day
expect {
GuestsCleanupJob.set(wait_until: date).perform_later
}.to have_enqueued_job.at(date)
end
it 'enque the job without usec change' do
date = Time.current.utc + 1.day
expect {
GuestsCleanupJob.set(wait_until: date).perform_later
}.to have_enqueued_job.at(date)
end
end The first spec is always green. Even on 3.9.1. The second spec, failed after b1e27e2 was introduced. :) |
@benoittgt found the commit, good job 👍. By a quick look
Yeah, I'm using 3.9 and I started an issue here with a MR to help to find a fix, so I'm on it ;-). Reverting would be just a quick fix until the real cause is found. Since there is no other issue opened yet, it looks like I am the only one with this problem, so maybe it is not so important to revert it until a real solution is found which can take some time.
The question for me is: Why is
So maybe calling Edit: It could be implemented in def at(date)
@at = Time === date ? Time.at(date.to_f) : date
self
end It fixes the spec, too. |
A quick question: why just not to change In that way, it kinda returns to what we have in 3.9. Or if it doesn't work for some reason use I solved my issue by wrapping |
Good job bisecting, I had a strong suspicion it was my change that led to this behavior change. 🤦♂ Let's dissect the problem into two by following how Rails does it.
I still disagree that we have to pass our expected values through AJ's serialization before comparing them to AJ, we'll have to keep track of which arguments were regular values and which were matchers, only pass regular values. I imagine this as more code than the approach above. There could be potential failures in existing specs, with any taken approach that involves rounding e.g.: now = Time.now
expect {
SomeJob.set(wait_until: now).perform_later
}.to enqueue_job.at(be_within(0.2.seconds).from(now)) The above will round Yet another possible solution I personally favour is to fix |
We have a solution on how to get the problem of @at = Time.at(@at.to_f) if Time === @at
values_match?(@at, Time.at(job[:at])) We obviously don't follow how Rails does it in their matchers, but neither we did that before, our AJ/AM matchers are all written from scratch. Obviously, the same problem might pop up for the arguments, e.g.: SomeJob.perform_later([1.day.ago, 2.days.ago]) but tackling it would be working around serialization/deserialization bugs that we're not responsible for. |
@syakovyn |
Closed by #2304 |
This is a failing spec to reproduce issue #2299.