-
Notifications
You must be signed in to change notification settings - Fork 13
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
Is dripper/perform.rb
locating wrong campaign
when database is MySQL?
#39
Comments
Wow, you've put a ton of work into this issue before posting, and we super appreciate that. Than you for all the info! You've actually stumbled upon something I patched in my company's app before I became a contributor to this project directly and I forgot to ever bring up. That's a bummer 🙁. While my usage of Caffeinate on the 'application' side of our application is fine (we only ever call config.before(:each) do
# NOTE: Caffeinate maintains a couple of class-variables under the hood
# that don't get reset between specs (while the db records they cache do
# get truncated). This resets the appropriate class-variables between specs
# NOTE: Caffeinate.dripper_collection gives us all the drippers in the project
Caffeinate.dripper_collection.instance_variable_get(:@registry).values.each do |drppr|
drppr.safe_constantize.class_eval { @caffeinate_campaign = nil }
end
end 🤔 |
Thank you! That fixed it. setup do
Caffeinate.dripper_collection.instance_variable_get(:@registry).values.each do |drppr|
drppr.safe_constantize.class_eval { @caffeinate_campaign = nil }
end
end Updated working source of caffeinate_test.rbrequire "test_helper"
class CaffeinateTest < ActionDispatch::IntegrationTest
# See: https://github.com/joshmn/caffeinate/issues/39
# NOTE: Caffeinate maintains a couple of class-variables under the hood
# that don't get reset between specs (while the db records they cache do
# get truncated). This resets the appropriate class-variables between specs
# NOTE: Caffeinate.dripper_collection gives us all the drippers in the project
setup do
Caffeinate.dripper_collection.instance_variable_get(:@registry).values.each do |drppr|
drppr.safe_constantize.class_eval { @caffeinate_campaign = nil }
end
end
test "foo" do
campaign = Caffeinate::Campaign.find_or_create_by!(name: "Test", slug: "test")
user = User.create!(name: "foo", email: "foo@foo")
subscriber = Subscriber.create!(name: "bar", email: "bar@bar")
assert Caffeinate::CampaignSubscription.count == 0
campaign.subscribe(subscriber, user: user)
assert user.before_drip_run_counter.to_i == 0
TestDripper.perform!
user.reload
assert user.before_drip_run_counter == 1
sleep 1.seconds
TestDripper.perform!
user.reload
assert user.before_drip_run_counter == 2
end
test "foo-bar" do
campaign = Caffeinate::Campaign.find_or_create_by!(name: "Test", slug: "test")
user = User.create!(name: "bar", email: "bar@bar")
subscriber = Subscriber.create!(name: "foo", email: "foo@foo")
########################################################
# Here we're calling it as TestDripper.subscribe
# rather than campaign.subscribe
TestDripper.subscribe(subscriber, user: user)
########################################################
assert user.before_drip_run_counter.to_i == 0
TestDripper.perform!
user.reload
assert user.before_drip_run_counter == 1
sleep 1.seconds
TestDripper.perform!
user.reload
assert user.before_drip_run_counter == 2
end
end |
@jon-sully thank you! @erwin the campaigns are indeed memoized. I have actually shot myself in the foot with this before too 😬 @jon-sully what do you think about |
Yeah I think having a small macro like that and an explanation in the readme is a good way to go. That's pretty close to how Sidekiq does it, which I think is good |
Added a convenience method called |
I've been struggling with this one non-stop since Saturday. Please pardon me if I have missed something. It was a lot of work to slice this out of my app and find the breaking point. It's very subtle.
I've done my best to create a minimal reproducible test. I'm not sure if it impacts production or only the test harness.
The issue I'm seeing is that when using MySQL, the first call to
perform!
works fine.caffeinate/lib/caffeinate/dripper/perform.rb
Line 17 in 0356067
But in subsequent calls, the value of
campaign
is set incorrectly (I think to the value from the previous call)caffeinate/lib/caffeinate/dripper/perform.rb
Line 40 in 0356067
The result is
upcoming_mailings
returns an empty set on subsequent calls toperform
, and thus the campaign is only run the first time.Debugging the `Caffeinate::CampaignSubscription` result set inside of `Perform!`
I modified
perform
to dump theCaffeinate::CampaignSubscription
set as it's filtered so I can see what was happening:caffeinate/lib/caffeinate/dripper/perform.rb
Line 19 in 0356067
Print the
Caffeinate::CampaignSubscription
inside ofperform!
:I created an empty
rails 7
project that uses sqlite3 and the following works as expected:.perform!
on the campaign, to execute both of the drippers connected to the campaign.However, when I do the same thing on a blank rails 7 project that uses MySQL, when
perform!
is called in the 2nd test, theCaffeinate::CampaignSubscription
result set is blank (becausecampaign
is pointing to an invalid record, and thus no drips are sent the second time around.From inside of calls to
perform!
, if we print all of the active campaigns with:Caffeinate::CampaignSubscription.active
it contains:You see how campaign.id does not match
CAFFEINATE_CAMPAIGN_ID
... So when we print the active campaigns where the campaign id matches, we get an empty set:Reproducing...
Versions:
Create a new rails7 project to reproduce the bug:
application_dripper.rb
app/drippers/application_dripper.rb
test_dripper.rb
app/drippers/test_dripper.rb
test_action.rb
app/actions/test_action.rb
caffeinate_test.rb
test/integration/caffeinate_test.rb
If you run the above, but do not specify
-d mysql
(using the default sqlite3), then it will work fine.But if you run it with mysql, it will fail.
test foo
andtest foo-bar
should be equivalent, producing equivalent output, but running:bin/rails test
you will get:test output for mysql version
When you run the same thing under sqlite3 though, the test passes as you would expect.
create the sqlite3 version of the same app
rails new --minimal repro2 cd repro2 bin/bundle add caffeinate awesome_print table_print rails g caffeinate:install rails g model User name email before_drip_run_counter:integer rails g model Subscriber name email rails db:migrate
test output for sqlite3 version
One other issue that I also see when using
MySQL
but not when usingsqlite3
...If we call
subscribe
as:Instead of:
In the second test that calls
TestDripper.subscribe
it will return with:When I run the same using
sqlite3
it works fine...Reproducing second issue...
Use the same content for
application_dripper.rb
,test_dripper.rb
andtest_action.rb
.Alternate version of caffeinate_test.rb
output when running under sqlite3
test output when running under mysql
Hopefully you made it this far... That's an awful lot to digest. It's been quite a challenge trying to trace exactly what is happening. Hopefully you've got some ideas on how we can patch caffeinate to get these test to pass, or if I'm just misunderstanding something basic and using caffeinate incorrectly.
Thank you.
The text was updated successfully, but these errors were encountered: