Como corrigir um problema com o empacotador que exige a versão mais recente do gem quando preciso exigir uma versão diferente?

8

Estive coçando minha cabeça com essa por quase duas semanas. Eu tenho um servidor Ubuntu 14.04 com o rbenv instalado executando vários sites diferentes do Rails, alguns deles em versões mais antigas do Rails, outros na versão mais recente.

Eu tenho 2 sites em particular que exigem uma versão diferente do puma_worker_killer, 1 requer 0.1.0 e o outro 0.1.1. Ambos os sites usam o Ruby 2.5.3.

Quando inicio o servidor RAILS_ENV=dev3 bundle exec pumactl -F ./config/puma.rb start, recebo o seguinte erro nos logs e o site trava:

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)

No começo, pensei que poderia ter havido um problema com o rbenv, pois eu tinha as gemas instaladas em ~ / .gem, em vez de em ~ / .rbenv, então coloquei todos os rubis em ~ / .gem e os instalei recentemente no correto pasta rbenv com bundle installe ainda recebo o mesmo problema.

Agora, neste momento, quero esclarecer que fiz uma extensa pesquisa on-line sobre esse assunto e sei que posso fazer muitas coisas para resolver isso.

Eu sei que posso apenas mudar a versão e bundle update puma_worker_killer.

Também sei que posso remover a versão mais recente executando gem uninstall puma_worker_killere escolhendo 0.1.1, mas isso significaria que as dependências no outro site não seriam atendidas.

Fiz algumas investigações no código-fonte do bundler e posso ver que ele é causado pela seguinte linha de código:

return if activated_spec.version == spec.version

Quando executado no contexto do bundler usando bundle exectanto o activated_spece speccorresponder, o que significa que o seguinte código nesse método ( check_for_activated_spec!) não é executado. Por alguma razão, ao executar o comando acima para iniciar o servidor, activated_spec(a gema ativada) é a versão mais recente (0.1.1) e não a listada no Gemfile (0.1.0), o que significa que não retorna e lança o erro acima.

Também devo mencionar que também parece haver o mesmo problema com o get_process_mem, que é uma das dependências do puma_worker_killer. Ele reclama de já ativar o 0.2.5, mas meu Gemfile quer o 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)

Entendo que o empacotador deve carregar a versão listada no Gemfile ao usá-lo bundle execpara combater esse problema de ter várias versões da mesma joia.

Eu sei que também poderia criar um gemset separado (que pode ser feito com o rbenv aparentemente) que possui diferentes versões do puma_worker_killer e executar rbenv local 2.5.3-pwk0.1.0ou, rbenv local 2.5.3-pwk0.1.1dependendo da versão que eu quero, dentro do projeto, mas isso parece um exagero para o que eu quero alcançar.

Nesse ritmo, sou tentado a atualizar todos os sites com a versão mais recente do puma_worker_killer e do get_process_mem e depois bloqueá-los e remover todas as versões mais antigas do servidor, mas acho que não preciso fazer isso.

Alguém sabe o que está acontecendo aqui ou se estou fazendo algo flagrantemente errado?

Abaixo está o código que eu uso para usar o puma_worker_killer na minha configuração do 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
fonte
1
Normalmente, defino meu ambiente dentro da janela de encaixe para cada projeto, para que a instalação não interfira. Também não é tão difícil montar um diretório da máquina host na instância do docker, embora a manutenção da imagem às vezes seja um pouco difícil. Nesse caso, costumo configurar uma janela de encaixe nova e montar a partir do diretório host novamente para começar de novo.
darkash
Vale a pena excluir o arquivo Gemfile.lock e, em seguida, executar a instalação do pacote novamente - ele removerá todos os números de versão não especificados e tentará criar um conjunto de gemas compatíveis entre si, gerando um erro e explicando os confrontos se não for possível #
Mark
@arkash sim docker seria o caminho ideal para ir com isso. Isso é na calha para melhorias futuras, mas eu só estou tentando superar esse problema imediato que eu possa obter todos os sites para se comportar muito bem uns com os outros no mesmo servidor
Arran Scott
1
@ Marcos sim, eu sei que eu poderia fazer isso também, mas isso é apenas semelhante à execução bundle update puma_worker_killernão é realmente uma vez que só vai usar a nova versão do puma_worker_killer que está instalado no servidor
Arran Scott

Respostas:

1

O que está acontecendo aqui é basicamente que você tem várias versões da gema em seu sistema.

Na maioria das vezes, não causava problemas, porque bundle execcarregava dinamicamente as versões necessárias para o seu aplicativo.

Em alguns casos, as gemas terão arquivos binários incluídos. Nesse caso bundle exec, não ajudará porque você pode ter apenas uma versão vinculada em um momento.

Basicamente, se você quiser chamar o binário por alias, precisará usar o gemset separado para cada aplicativo.

Se você deseja manter todas as gemas em um só lugar, pode chamar arquivos binários diretamente.

No seu caso, será:

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

A _<version>_construção permite especificar a versão do arquivo binário que você deseja executar.

Você também pode criar seu binário personalizado, como fake_pumactldentro do projeto, que verificará Gemfile.locke fará proxy automaticamente da sua chamada para a biblioteca e especificará a versão automaticamente para você. Outra maneira é analisar a versão da gema pelo shell script e colocá-lo em vez de _<version>_na sua chamada.

Aqui está o breve exemplo

$ 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_versionA variável pode ser definida a partir do resultado de um comando bash, do qual extrairá a versão gem Gemfile.lock.

achempion
fonte
Obrigado pela sua resposta. Eu sei que poderia seguir o caminho da criação de um Gemset separado, mas realmente não queria fazer isso. Gosto da maneira como você mencionou ao especificar um arquivo binário específico com a versão. Eu apenas tentei no entanto e parece não funcionar. Neste aplicativo específico, tenho o Puma 3.7.0 como a versão especificada no Gemfile, mas também tenho o 4.1.0 instalado. Eu executo o seguinte comando: RAILS_ENV=dev3 bundle exec pumactl _4.1.0_ -F ./config/puma.rb starte ele inicia a 3.7.0 e não a 4.1.0 ( Version 3.7.0 (ruby 2.5.3-p105), codename: Snowy Sagebrush)
Arran Scott
Você também pode me explicar como faria isso, 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
Estendi
Obrigado. Estranhamente, isso funciona quando estou fora da raiz de um projeto Rails, mas quando eu coloco um CD em um dos diretórios não 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 Preciso descobrir por que isso acontece, mas você realmente respondeu minha pergunta, então obrigado e vou marcá-lo como respondido
Arran Scott
Você poderia substituir pumactl ${puma_version} -vcom ${pumactl_path} -vbem, deve funcionar dentro do diretório projeto onde pumactl_pathserá definido como caminho para uma forlder dentro gem binário. Talvez Gemfile.lockinfluencie o resultado do seu comando porque ele contém uma versão mais antiga.
achempion em 21/04