Skip to content

Avoid draining pool in gardener cleanup#26

Closed
wtn wants to merge 1 commit into
socketry:mainfrom
wtn:gardener
Closed

Avoid draining pool in gardener cleanup#26
wtn wants to merge 1 commit into
socketry:mainfrom
wtn:gardener

Conversation

@wtn

@wtn wtn commented Mar 13, 2026

Copy link
Copy Markdown
Contributor

When a Sync scope exits while the gardener is waiting, Async::Cancel interrupts @condition.wait(@mutex) inside @mutex.synchronize, producing a ThreadError warning. The gardener's ensure also called self.closedrain, which could block if resources are still acquired during teardown.

warn: Async::Task: Async::Pool::Controller Gardener
  Task may have ended with unhandled exception.
    ThreadError: Attempt to unlock a mutex which is not locked
    → async-pool-0.11.2/lib/async/pool/controller.rb:132 in `synchronize'
    Caused by Async::Cancel: Task was cancelled

The gardener's ensure now force-retires resources directly instead of calling close/drain.

Types of Changes

  • Bug fix.

Contribution

@wtn wtn changed the title Avoid draining pool in gardener cleanup. Avoid draining pool in gardener cleanup Mar 13, 2026
Comment thread lib/async/pool/controller.rb Outdated
Co-authored-by: Claude <noreply@anthropic.com>
@samuel-williams-shopify

Copy link
Copy Markdown

Hmm, I'm not sure about this issue.

I could reproduce a hang:

Sync do
	policy = proc{|pool| pool.prune(0)}
	pool = Async::Pool::Controller.new(Async::Pool::Resource, policy: policy)
	
	# Acquire a resource (starts the gardener) but don't release it
	pool.acquire
	
	# Let gardener start and enter its wait loop
	sleep 0.05
end

But this program is malformed, since the resource is never released, that's an expected hang. The pool is designed to gracefully clean up. If you rewrite the program:

Sync do
	policy = proc{|pool| pool.prune(0)}
	pool = Async::Pool::Controller.new(Async::Pool::Resource, policy: policy)
	
	# Acquire a resource (starts the gardener) but don't release it
	pool.acquire do
		# Let gardener start and enter its wait loop
		sleep 0.05
	end
end

It does not hang.

I think it's better to have correct semantics and hang when the program is malformed. If there is a valid program that results in a hang, feel free to open a new issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants