gel-rb / gel

A modern gem manager: Gel is a lightweight alternative to Bundler

Home Page:https://gel.dev

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

NoMethodError: undefined method `name' for nil:NilClass

sj26 opened this issue · comments

I've been getting some odd errors when starting Puma using gel:

Traceback (most recent call last):
	20: from /Users/sj26/.local/gel/2.6.0/gems/puma-3.12.0/bin/puma-wild:31:in `<main>'
	19: from /Users/sj26/.local/gel/2.6.0/gems/puma-3.12.0/lib/puma/cli.rb:78:in `run'
	18: from /Users/sj26/.local/gel/2.6.0/gems/puma-3.12.0/lib/puma/launcher.rb:184:in `run'
	17: from /Users/sj26/.local/gel/2.6.0/gems/puma-3.12.0/lib/puma/cluster.rb:466:in `run'
	16: from /Users/sj26/.local/gel/2.6.0/gems/puma-3.12.0/lib/puma/cluster.rb:133:in `spawn_workers'
	15: from /Users/sj26/.local/gel/2.6.0/gems/puma-3.12.0/lib/puma/cluster.rb:133:in `times'
	14: from /Users/sj26/.local/gel/2.6.0/gems/puma-3.12.0/lib/puma/cluster.rb:137:in `block in spawn_workers'
	13: from /Users/sj26/.local/gel/2.6.0/gems/puma-3.12.0/lib/puma/cluster.rb:137:in `fork'
	12: from /Users/sj26/.local/gel/2.6.0/gems/puma-3.12.0/lib/puma/cluster.rb:137:in `block (2 levels) in spawn_workers'
	11: from /Users/sj26/.local/gel/2.6.0/gems/puma-3.12.0/lib/puma/cluster.rb:273:in `worker'
	10: from /Users/sj26/.local/gel/2.6.0/gems/puma-3.12.0/lib/puma/runner.rb:162:in `start_server'
	 9: from /Users/sj26/.local/gel/2.6.0/gems/puma-3.12.0/lib/puma/runner.rb:155:in `app'
	 8: from /Users/sj26/.local/gel/2.6.0/gems/puma-3.12.0/lib/puma/configuration.rb:243:in `app'
	 7: from /Users/sj26/.local/gel/2.6.0/gems/puma-3.12.0/lib/puma/configuration.rb:318:in `load_rackup'
	 6: from /Users/sj26/.local/gel/2.6.0/gems/puma-3.12.0/lib/puma/configuration.rb:305:in `rack_builder'
	 5: from /usr/local/Cellar/gel/0.3.0/lib/gel/compatibility/rubygems.rb:197:in `require'
	 4: from /usr/local/Cellar/gel/0.3.0/lib/gel/environment.rb:581:in `resolve_gem_path'
	 3: from /usr/local/Cellar/gel/0.3.0/lib/gel/locked_store.rb:87:in `gems_for_lib'
	 2: from /usr/local/Cellar/gel/0.3.0/lib/gel/locked_store.rb:87:in `each'
	 1: from /usr/local/Cellar/gel/0.3.0/lib/gel/locked_store.rb:87:in `block in gems_for_lib'
/usr/local/Cellar/gel/0.3.0/lib/gel/environment.rb:583:in `block in resolve_gem_path': undefined method `name' for nil:NilClass (NoMethodError)

It's coming from here:

https://github.com/gel-rb/gel/blob/v0.3.0/lib/gel/environment.rb#L583

I added a pp(path: path, subdir: subdir) if gem.nil? in there and got:

{:path=>"active_record/railtie", :subdir=>nil}
{:path=>"i18n", :subdir=>nil}

Then I ran it again and got:

{:path=>"active_support", :subdir=>nil}
{:path=>"i18n", :subdir=>nil}

It seems to change subtly on each invocation. Race condition?

Interestingly, I just got:

{{:path:path=>=>"rack", :subdir=>nil}
"rack", :subdir=>nil}

But I think that might be due to Puma starting some child processes.

Oh, I'm going to guess this is due to fork(). :-/

This was biting me again today, so I've been doing some digging.

These two lines seem to be in some sort of race condition:

g = @inner.gems(inner_versions)
@inner.libs_for_gems(inner_versions) do |name, version, subs|
subs.each do |subdir, files|
v = [g[name], subdir]
files.each do |file|
@lib_cache[file] << v
end
end
end

The g variable is being populated with an incomplete list of gems, then the followign libs_for_gems block seems to yield entries where for a given name there is no g[name]. This can be verified by switching v = [g[name], subdir] to v = [g.fetch(name), subdir]

This only occurs for me when starting puma in clustered mode with more than one worker. I'm guessing that multiple forks from the same parent process leave this in a bad state somehow, and causes incomplete data to be returned from the underlying Gel::Store because the Gel::DB isn't fully flushed before fork — that's the only way I can conceive of this getting into such an inconsistent state.

I seem to be using the SDBM implementation:

Gel::Environment.with_root_store { |store| store.instance_variable_get(:@stores)["ruby"].instance_variable_get(:@primary_db) }
=> #<Gel::DB::SDBM:0x00007fca87da9810 @root="~/.local/gel/ruby", @name="store", @sdbm=#<SDBM:0x00007fca87da97c0>, @transaction=nil, @monitor=#<Monitor:0x00007fca87da9798 @mon_mutex=#<Thread::Mutex:0x00007fca87da9748>, @mon_mutex_owner_object_id=70253919685580, @mon_owner=nil, @mon_count=0>>

Commenting out the SDBM implementation of Gel::DB and using the PStore fallback solves this issue for me.

I still get this issue today, and I think this is what led me to stop using gel last time I tried 😢

10:26:32        puma | /opt/homebrew/Cellar/gel/HEAD-ae273ca_1/lib/gel/environment.rb:557:in `block in scan_for_path': undefined method `name' for nil:NilClass (NoMethodError)
10:26:32        puma | 	from /opt/homebrew/Cellar/gel/HEAD-ae273ca_1/lib/gel/locked_store.rb:87:in `block in gems_for_lib'
10:26:32        puma | 	from /opt/homebrew/Cellar/gel/HEAD-ae273ca_1/lib/gel/locked_store.rb:87:in `each'
10:26:32        puma | 	from /opt/homebrew/Cellar/gel/HEAD-ae273ca_1/lib/gel/locked_store.rb:87:in `gems_for_lib'
10:26:32        puma | 	from /opt/homebrew/Cellar/gel/HEAD-ae273ca_1/lib/gel/environment.rb:555:in `scan_for_path'
10:26:32        puma | 	from /opt/homebrew/Cellar/gel/HEAD-ae273ca_1/lib/gel/environment.rb:572:in `resolve_gem_path'
10:26:32        puma | 	from /opt/homebrew/Cellar/gel/HEAD-ae273ca_1/lib/gel/compatibility/rubygems.rb:251:in `require'
10:26:32        puma | 	from /Users/sj26/.local/gel/ruby/gems/activesupport-6.1.3/lib/active_support/dependencies.rb:332:in `block in require'
10:26:32        puma | 	from /Users/sj26/.local/gel/ruby/gems/activesupport-6.1.3/lib/active_support/dependencies.rb:299:in `load_dependency'
10:26:32        puma | 	from /Users/sj26/.local/gel/ruby/gems/activesupport-6.1.3/lib/active_support/dependencies.rb:332:in `require'
10:26:32        puma | 	from /Users/sj26/.local/gel/git/omniauth-github-967d76979b6bf/lib/omniauth/strategies/github.rb:1:in `<top (required)>'

Commenting out the SDBM implementation of Gel::DB and using the PStore fallback solves this issue for me.

SDBM support has been dropped because it was removed from stdlib, so maybe this is better now?