¿Cómo solucionar un problema con el paquete que requiere la última versión de gem cuando necesito una versión diferente?

8

He estado rascándome la cabeza con este por cerca de 2 semanas. Tengo un servidor Ubuntu 14.04 con rbenv instalado que ejecuta varios sitios web de Rails diferentes, algunos de ellos en versiones anteriores de Rails, algunos de ellos en la última versión.

Tengo 2 sitios web en particular que requieren una versión diferente de puma_worker_killer, 1 requiere 0.1.0 y el otro 0.1.1. Ambos sitios web usan Ruby 2.5.3.

Cuando inicio el servidor RAILS_ENV=dev3 bundle exec pumactl -F ./config/puma.rb start, aparece el siguiente error en los registros y el sitio web se bloquea:

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)

Al principio pensé que podría haber sido un problema con rbenv ya que tenía las gemas instaladas en ~ / .gem en lugar de en ~ / .rbenv, así que agregué todos los rubíes en ~ / .gem y los instalé nuevamente en el lugar correcto carpeta rbenv con bundle instally sigo teniendo este mismo problema.

Ahora, en este punto, quiero aclarar que he realizado una extensa investigación sobre este tema en línea y sé que puedo hacer muchas cosas para resolverlo.

Sé que solo puedo cambiar la versión y bundle update puma_worker_killer.

También sé que puedo eliminar la última versión haciendo gem uninstall puma_worker_killery eligiendo 0.1.1, pero esto significaría que las dependencias en el otro sitio web no se cumplirían.

He profundizado en el código fuente del bundler y puedo ver que es causado por la siguiente línea de código:

return if activated_spec.version == spec.version

Cuando se ejecuta en el contexto de bundler utilizando bundle exectanto el activated_specy el specpartido, lo que significa que el siguiente código en ese método ( check_for_activated_spec!) no se ejecuta. Por alguna razón, cuando se ejecuta el comando anterior para iniciar el servidor, activated_spec(la gema activada) es la última versión (0.1.1) y no la que figura en el Gemfile (0.1.0), lo que significa que no regresa y arroja El error anterior.

También debo mencionar que también parece haber el mismo problema con get_process_mem, que es una de las dependencias de puma_worker_killer. Se queja de que ya está activando 0.2.5 pero mi Gemfile quiere 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)

Tengo entendido que el bundler debe cargar la versión listada en el Gemfile cuando se usa bundle execpara contrarrestar este mismo problema de tener múltiples versiones de la misma gema.

Sé que también podría crear un conjunto de gemas por separado (que aparentemente se puede hacer con rbenv) que tiene diferentes versiones de puma_worker_killer en ellas y luego se ejecuta rbenv local 2.5.3-pwk0.1.0o rbenv local 2.5.3-pwk0.1.1depende de la versión que quiero, dentro del proyecto, pero parece excesivo para lo que quiero lograr.

A este ritmo, estoy tentado a actualizar todos los sitios web con la última versión de puma_worker_killer y get_process_mem y luego bloquearlos y eliminar todas las versiones anteriores del servidor, pero no creo que deba hacerlo.

¿Alguien sabe lo que está sucediendo aquí o si estoy haciendo algo notoriamente mal?

A continuación se muestra el código que uso para usar puma_worker_killer en mi configuración de puma.

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
Arran Scott
fuente
1
Por lo general, configuro mi entorno dentro de la ventana acoplable para cada proyecto, por lo que la configuración no interferirá entre sí. Tampoco es tan difícil montar un directorio desde la máquina host a la instancia de acoplador, aunque a veces mantener la imagen puede ser un poco difícil. En ese caso, generalmente configuro una ventana acoplable nueva y la montaje desde el directorio del host nuevamente para comenzar de nuevo.
darkash
Vale la pena eliminar su archivo Gemfile.lock y luego volver a ejecutar la instalación del paquete: eliminará todos los números de versión que no están especificados e intentará construir un conjunto de gemas que sean compatibles entre sí, arrojando un error y explicando los enfrentamientos si no es posible
Mark
@darkash sí docker sería la forma ideal de hacerlo. Eso está en camino para futuras mejoras, pero solo estoy tratando de superar este problema inmediato para poder hacer que todos los sitios web se comporten bien entre sí en el mismo servidor
Arran Scott
1
@ Mark, sí, sé que también podría hacerlo, pero eso es similar a la ejecución, bundle update puma_worker_killer¿no es así, ya que solo usará la versión más reciente de puma_worker_killer que está instalada en el servidor
Arran Scott,

Respuestas:

1

Lo que está sucediendo aquí es que básicamente tienes varias versiones de la gema en tu sistema.

La mayoría de las veces no causó problemas porque bundle execcargará dinámicamente las versiones requeridas para su aplicación.

En algunos casos, las gemas tendrán archivos binarios incluidos. Tal caso bundle execno ayudará porque solo puede tener una versión vinculada en un momento.

Básicamente, si desea llamar al binario por alias, debe usar gemas separadas para cada aplicación.

Si desea mantener todas las gemas en un solo lugar, puede llamar directamente a archivos binarios.

En tu caso será:

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

La _<version>_construcción le permite especificar la versión del archivo binario que desea ejecutar.

También puede crear su binario personalizado, como fake_pumactldentro del proyecto, que verificará Gemfile.locky enviará automáticamente su llamada a la biblioteca y especificará la versión automáticamente. Otra forma es analizar la versión de gema por script de shell y poner este script en lugar de _<version>_en su llamada.

Aquí está el breve ejemplo.

$ 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_versionLa variable se puede definir a partir del resultado de un comando bash que extraerá la versión de la gema Gemfile.lock.

achempion
fuente
Gracias por tu respuesta. Sé que podría seguir el camino de crear un Gemset separado, pero realmente no quería hacer eso. Me gusta la forma en que mencionó la especificación de un archivo binario específico con la versión. Sin embargo, acabo de probarlo y no parece funcionar. En esta aplicación específica tengo Puma 3.7.0 como la versión especificada en Gemfile, pero también tengo instalado 4.1.0. RAILS_ENV=dev3 bundle exec pumactl _4.1.0_ -F ./config/puma.rb startEjecuto el siguiente comando: y comienza 3.7.0 en su lugar y no 4.1.0 ( Version 3.7.0 (ruby 2.5.3-p105), codename: Snowy Sagebrush)
Arran Scott
¿Puedes explicarme cómo harías esto, por favor? 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.
Arran Scott,
He extendido la respuesta
achempion
Gracias. Extrañamente, esto funciona cuando estoy fuera de la raíz de un proyecto de Rails, pero luego cuando me meto en uno de los directorios no funciona ... ➜ app_root git:(develop) ✗ gem install puma -v 3.12.0 Building native extensions. This could take a while... Successfully installed puma-3.12.0 Done installing documentation for puma after 1 seconds 1 gem installed ➜ app_root git:(develop) ✗ pumactl _3.12.0_ -v 3.7.0 Necesito entender por qué, pero realmente has respondido mi pregunta, así que gracias y lo marcaré como respondido
Arran Scott
También puede reemplazar pumactl ${puma_version} -vcon ${pumactl_path} -v, debería funcionar dentro del directorio del proyecto donde pumactl_pathse definirá como la ruta a un binario dentro de forlder de gemas. Tal vez Gemfile.lockinfluya en el resultado de su comando porque contiene una versión anterior.
Achempion