Skip to content

Allow Future callbacks to re-enter completed parents - #128

Open
dailyun wants to merge 1 commit into
samber:masterfrom
dailyun:codex/future-callback-reentry
Open

dailyun wants to merge 1 commit into
samber:masterfrom
dailyun:codex/future-callback-reentry

Conversation

@dailyun

@dailyun dailyun commented Oct 20, 2026

Copy link
Copy Markdown

A Then callback that calls its parent Future's Collect() deadlocks: the parent's done channel is only closed after the callback returns. Calling Cancel() or registering another callback on that parent also blocks on its mutex. Re-entering the original resolve callback blocks on sync.Once.

Publish the result and close done under the mutex, then run the existing synchronous callback chain after both the mutex and completion guard have been released. The first resolution/rejection still wins. This also means collecting the parent no longer waits for its descendant callbacks to finish.

Five regression tests cover collecting resolved/rejected parents, cancelling a parent, chaining another callback from it, and attempting another resolution inside a callback. Each test reproduces a timeout against the unmodified base 502998f.

Validation on Go 1.26.7 / macOS arm64:

  • Full go test -race ./..., build, vet, staticcheck and golangci-lint pass (0 lint issues).
  • New regression tests pass with -race -count 1000.
  • A broader 100-repeat Future run hits the existing TestFutureOrder scheduling assumption. Repeating that unchanged test on base 502998f fails the same way: it expects the caller's counter increment to precede an already-started goroutine. That test is left unchanged.
  • gofmt and git diff --check pass.

Developed and tested with OpenAI Codex assistance; no human review is claimed.

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.

1 participant