Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to fix issue with bundler requiring latest version of gem when I need to require a different version?

I've been scratching my head with this one for close to 2 weeks. I have an Ubuntu 14.04 server with rbenv installed running a number of different Rails websites, some of them on older versions of Rails, some of them on the latest version.

I have 2 websites in particular that both require a different version of puma_worker_killer, 1 requires 0.1.0 and the other 0.1.1. Both these websites use Ruby 2.5.3.

When I start the server with RAILS_ENV=dev3 bundle exec pumactl -F ./config/puma.rb start I get the following error in the logs and the website hangs:

You have already activated puma_worker_killer 0.1.1, but your Gemfile requires puma_worker_killer 0.1.0. Prepending `bundle exec` to your command may solve this. (Gem::LoadError)

At first I thought it may've been an issue with rbenv as I had the gems installed in ~/.gem instead of in ~/.rbenv so I've nuked all rubies in ~/.gem and installed them freshly into the correct rbenv folder with bundle install and I still get this same issue.

Now at this point I want to clarify that I've done extensive research on this subject online and I know that I can do many things to solve this.

I know I can just change the version and bundle update puma_worker_killer.

I also know I can remove the latest version by doing gem uninstall puma_worker_killer and choosing 0.1.1 but this would mean the dependencies on the other website wouldn't be met.

I've done some digging into the source code of bundler and can see that it's caused by the following line of code:

return if activated_spec.version == spec.version

When running in the context of bundler using bundle exec both the activated_spec and spec match, meaning that the following code in that method (check_for_activated_spec!) doesn't run. For some reason, when running the command above to start the server, activated_spec (the activated gem) is the latest version (0.1.1) and not the one listed in the Gemfile (0.1.0), meaning it doesn't return and throws the error above.

I should also mention that there also seems to be the same issue with get_process_mem, which is one of the dependencies of puma_worker_killer. It complains of already activating 0.2.5 but my Gemfile wants 0.2.4:

You have already activated get_process_mem 0.2.5, but your Gemfile requires get_process_mem 0.2.4. Prepending `bundle exec` to your command may solve this. (Gem::LoadError)

It is my understanding of bundler that it should load the version listed in the Gemfile when using bundle exec to counteract this very problem of having multiple versions of the same gem.

I know I could also create a separate gemset (which can be done with rbenv apparently) that has different versions of puma_worker_killer in them and then run rbenv local 2.5.3-pwk0.1.0 or rbenv local 2.5.3-pwk0.1.1 depending on the version I want, inside the project, but that seems overkill for what I want to achieve.

At this rate I'm tempted to just update all websites with the latest version of both puma_worker_killer and get_process_mem and then lock them in and remove all older versions on the server, but I don't think I should have to do that.

Does anyone know what's happening here or whether I'm doing something glaringly wrong?

Below is the piece of code I use to use puma_worker_killer in my puma config.

before_fork do
  require 'puma_worker_killer'

  PumaWorkerKiller.config do |config|
    config.ram           = 1024 # mb
    config.frequency     = 5 # seconds
    config.percent_usage = 0.98
    config.rolling_restart_frequency = 12 * 3600 # 12 hours in seconds
  end

  PumaWorkerKiller.start
end
like image 810
Arran Scott Avatar asked Nov 28 '19 07:11

Arran Scott


People also ask

How can I remove default version of bundler?

You have to delete the . gemspec file corresponding to the default gem you want to delete. So first, locate where those files are. Delete the one you don't need.


1 Answers

What is happening here is basically you have several versions of the gem in your system.

Most of the time it did not cause issues because bundle exec will dynamically load required versions for your application.

In some cases gems will have binary files included. It such case bundle exec will not help because you can have only one version linked in one moment.

Basically, if you want to call the binary by alias you have to use separate gemset for each application.

If you want to keep all the gems in one place you can call binary files directly.

In your case it will be:

RAILS_ENV=dev3 bundle exec pumactl _0.1.0_ -F ./config/puma.rb

The _<version>_ construction allows you to specify version of the binary file you want to run.

You can create your custom binary as well, like fake_pumactl inside the project which will check the Gemfile.lock and automatically proxy your call to the library and specify version automatically for you. Another way is to parse gem version by shell script and put this script instead of _<version>_ in your call.

Here is the brief example

$ gem install puma
Fetching puma-4.3.3.gem

$ gem install puma -v 4.3.0
Fetching puma-4.3.0.gem

$ pumactl -v
4.3.3

$ pumactl _4.3.0_ -v
4.3.0

$ ruby -v
ruby 2.6.3p62

$ export puma_version=_4.3.0_
$ pumactl ${puma_version} -v
4.3.0

puma_version variable can be defined from result of a bash command which will extract the gem version from Gemfile.lock.

like image 179
achempion Avatar answered Oct 12 '22 23:10

achempion