flipper
flipper copied to clipboard
Flipper Redis Adapter ignoring configuration block sometimes
When upgrading from flipper 1.1.2 to flipper 1.2.2 the behavior of the redis adapter changed.
Sometimes it initializes from my configuration block:
::Flipper.configure do |config|
config.adapter do
::Flipper::Adapters::Redis.new(
::Redis.new(:url => configuration.feature_flag_redis)
end
end
Other times, it ignores that block and uses the block at the bottom of the flipper redis adapter https://github.com/flippercloud/flipper/blob/0e996298dec5f05d4a9feb11369cb7db4e402a09/lib/flipper/adapters/redis.rb#L209
I edited my local copies of the gems to dump the stack to trace the problem (so some line numbers don't 100% line up).
When I start my rails application in puma, I see the redis adapter initializing 3 times. Once with the adapter constructed in my code and twice with the adapter constructed from the flipper redis adapter gem
If I make a request that gets the adapter I initialized, the page renders. If I make a request with the adapter initialized by the redis adapter, the page errors because the redis URL is incorrect.
The stack trace of the good adapter (the first one that intializes)
.rbenv/versions/3.1.4/lib/ruby/gems/3.1.0/gems/flipper-redis-1.2.2/lib/flipper/adapters/redis.rb:28:in `backtrace'
.rbenv/versions/3.1.4/lib/ruby/gems/3.1.0/gems/flipper-redis-1.2.2/lib/flipper/adapters/redis.rb:28:in `initialize'
.rbenv/versions/3.1.4/lib/ruby/gems/3.1.0/gems/feature-flag-0.13.2/lib/feature/flag/initializer/initializer.rb:50:in `new'
.rbenv/versions/3.1.4/lib/ruby/gems/3.1.0/gems/feature-flag-0.13.2/lib/feature/flag/initializer/initializer.rb:50:in `flipper_adapter'
.rbenv/versions/3.1.4/lib/ruby/gems/3.1.0/gems/feature-flag-0.13.2/lib/feature/flag/initializer/initializer.rb:31:in `block (2 levels) in configure_flipper'
.rbenv/versions/3.1.4/lib/ruby/gems/3.1.0/gems/flipper-1.2.2/lib/flipper/adapter_builder.rb:41:in `to_adapter'
.rbenv/versions/3.1.4/lib/ruby/gems/3.1.0/gems/flipper-1.2.2/lib/flipper/configuration.rb:29:in `adapter'
.rbenv/versions/3.1.4/lib/ruby/gems/3.1.0/gems/flipper-1.2.2/lib/flipper/engine.rb:54:in `block (3 levels) in <class:Engine>'
.rbenv/versions/3.1.4/lib/ruby/gems/3.1.0/gems/flipper-1.2.2/lib/flipper/configuration.rb:65:in `default'
.rbenv/versions/3.1.4/lib/ruby/gems/3.1.0/gems/flipper-1.2.2/lib/flipper.rb:46:in `instance'
.rbenv/versions/3.1.4/lib/ruby/3.1.0/forwardable.rb:232:in `memoizing?'
.rbenv/versions/3.1.4/lib/ruby/gems/3.1.0/gems/flipper-1.2.2/lib/flipper/middleware/memoizer.rb:67:in `memoized_call'
.rbenv/versions/3.1.4/lib/ruby/gems/3.1.0/gems/flipper-1.2.2/lib/flipper/middleware/memoizer.rb:45:in `call'
The stack trace of the bad adapters (the second 2)
.rbenv/versions/3.1.4/lib/ruby/gems/3.1.0/gems/flipper-redis-1.2.2/lib/flipper/adapters/redis.rb:28:in `backtrace'
.rbenv/versions/3.1.4/lib/ruby/gems/3.1.0/gems/flipper-redis-1.2.2/lib/flipper/adapters/redis.rb:28:in `initialize'
.rbenv/versions/3.1.4/lib/ruby/gems/3.1.0/gems/flipper-redis-1.2.2/lib/flipper/adapters/redis.rb:220:in `new'
.rbenv/versions/3.1.4/lib/ruby/gems/3.1.0/gems/flipper-redis-1.2.2/lib/flipper/adapters/redis.rb:220:in `block (2 levels) in <top (required)>'
.rbenv/versions/3.1.4/lib/ruby/gems/3.1.0/gems/flipper-1.2.2/lib/flipper/adapter_builder.rb:41:in `to_adapter'
.rbenv/versions/3.1.4/lib/ruby/gems/3.1.0/gems/flipper-1.2.2/lib/flipper/configuration.rb:29:in `adapter'
.rbenv/versions/3.1.4/lib/ruby/gems/3.1.0/gems/flipper-1.2.2/lib/flipper/engine.rb:54:in `block (3 levels) in <class:Engine>'
.rbenv/versions/3.1.4/lib/ruby/gems/3.1.0/gems/flipper-1.2.2/lib/flipper/configuration.rb:65:in `default'
.rbenv/versions/3.1.4/lib/ruby/gems/3.1.0/gems/flipper-1.2.2/lib/flipper.rb:46:in `instance'
.rbenv/versions/3.1.4/lib/ruby/3.1.0/forwardable.rb:232:in `memoizing?'
.rbenv/versions/3.1.4/lib/ruby/gems/3.1.0/gems/flipper-1.2.2/lib/flipper/middleware/memoizer.rb:67:in `memoized_call'
.rbenv/versions/3.1.4/lib/ruby/gems/3.1.0/gems/flipper-1.2.2/lib/flipper/middleware/memoizer.rb:45:in `call'
The branching happens with how the adapter builder constructs the redis adapter.
Of course, I can get around the problem if I set the env var FLIPPER_REDIS_URL
However, the documentation doesn't specify that the URL has to come from an env variable.
https://www.flippercloud.io/docs/adapters/redis
It's somewhat inconvenient to have to set the env variable. I have been trying to figure out what changed. I didn't need to set the env var in version 1.1.2.
@micahtessler I'm not sure how to reproduce this. It sounds like Flipper is getting used during the boot process prior to your custom config possibly? @bkeepers does it sound like that to you or do you have any different ideas?
One option to figure out where this is happening is to bundle open flipper and add something like caller inside the flipper configure block there to see the backtrace of where it's getting invoked from. Once you have that, it should be easier to determine why this is happening.
Can you give that a try and let me know if it helps?
@micahtessler I'm not sure how to reproduce this. It sounds like Flipper is getting used during the boot process prior to your custom config possibly? @bkeepers does it sound like that to you or do you have any different ideas?
I agree, that's what it sounds like.
I edited my local copies of the gems to dump the stack to trace the problem (so some line numbers don't 100% line up).
If youc an paste the whole stack trace, we should be able to tell if it's happening during app boot and where.
Not sure what you reference as the boot process. The first initialization happens correctly as you can see above, it calls into my initializer config. The second and third intializations happen incorrectly and occur afterwards.
so it there was a boot problem, I would expect the opposite, the first initialization would not get the config as it hadn't been set. The 2nd and third would pick up the correct config as it's set in a rails initilaizer.
What from the stack trace do you need to see specifically?
What from the stack trace do you need to see specifically?
From inside of the default redis configure block. If you bundle open flipper-redis you can add the require and pp caller in the screenshot. Restart your process and copy the backtrace that gets printed.