Introduce ForkTracker to automatically restart threads #344
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Summary
The Problem
When running puma or unicorn with multiple workers, they do some initial work in a process. When configured to preload the app, this can include the initialization of
Optimizely::Project
instances. When these objects are instantiated, there are threads that get started.After the initial process is done with its work, it forks into new processes. This kills the threads.
This is documented here but requires updating the server config. Instead, making the gem responsible for re-starting the threads itself removes this footgun and makes the initial setup easier.
Side note: If there's no appetite for including this or a similar change in the gem itself, adding that documentation to the README and the Ruby quickstart guide would be helpful. It took us awhile to track down what was happening 😅
The Fix
This proof of concept copies over Rails'
ActiveSupport::ForkTracker
that hooks intoProcess._fork
and allows us to re-start the threads automatically after forking. No extra configuration is needed by the user of the gem.As an alternative approach, the DataDog gem handles this nicely as well and could be used as inspiration.
Test plan
In an app that includes the gem, start puma or unicorn with multiple workers and see that the Optimizely classes no longer need to be re-initialized after forking and the datafile continues to be updated, etc.
I'm happy to add some tests to this if you'd want to move forward with this implementation.