Skip to content

perf(amp): avoid fibers in future adapter#1954

Open
simPod wants to merge 1 commit into
webonyx:masterfrom
simPod:perf/avoid-fiber-per-amp-continuation
Open

perf(amp): avoid fibers in future adapter#1954
simPod wants to merge 1 commit into
webonyx:masterfrom
simPod:perf/avoid-fiber-per-amp-continuation

Conversation

@simPod

@simPod simPod commented Jul 24, 2026

Copy link
Copy Markdown
Collaborator

Context

AmpFutureAdapter created an AMPHP Fiber for every promise continuation and aggregate. Wide GraphQL result graphs therefore retained many Fiber states and event-loop callbacks even when the underlying Futures only represented batched work.

Decision

Compose and aggregate Futures through map() and catch() callbacks, settling one DeferredFuture while retaining Promise fulfillment, rejection, and nested-Future flattening semantics.

Consequences

  • Reduces per-field allocation and event-loop scheduling for wide asynchronous result graphs.
  • Preserves deferred completion for genuinely asynchronous resolvers.
  • Adds coverage for nested Future fulfillment/recovery, fulfillment errors, aggregate key preservation, aggregate rejection, and resolution after rejection.

Benchmark

On the same wide GraphQL result graph with 838 parent objects and three Future-backed fields:

Adapter CPU time Peak memory
Synchronous adapter 1.48s 122MB
Existing AMPHP adapter 2.11s 274MB
This change 1.67-1.70s 149MB

Relative to the existing AMPHP adapter, this reduces CPU time by about 19% and peak memory by about 46%. The remaining overhead compared with the synchronous adapter is about 13-15% CPU and 22% memory.

Disclosure

This change was identified while migrating a production GraphQL application that is not yet fully migrated to asynchronous resolving. It is a step toward that migration, rather than a claim of end-to-end asynchronous production use.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors the AMPHP v3 AmpFutureAdapter to compose and aggregate Future continuations without creating a new Fiber per continuation/aggregate, aiming to reduce allocations and event-loop overhead for wide async GraphQL result graphs.

Changes:

  • Reworked AmpFutureAdapter::then() to settle a single DeferredFuture via Future::map()/catch() observation rather than async + await.
  • Reimplemented AmpFutureAdapter::all() to resolve/reject by observing each input Future, preserving array keys and avoiding aggregate await.
  • Added/expanded PHPUnit coverage for nested-future flattening, fulfillment callback exceptions, key preservation, aggregate rejection, and “stay rejected” behavior.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
src/Executor/Promise/Adapter/AmpFutureAdapter.php Removes per-continuation fibers by observing futures with map()/catch() and settling a shared DeferredFuture.
tests/Executor/Promise/AmpFutureAdapterTest.php Adds tests covering nested future unwrapping, rejection/exception behavior, key preservation, and aggregate failure semantics.
CHANGELOG.md Documents the behavioral/performance fix under Unreleased.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/Executor/Promise/Adapter/AmpFutureAdapter.php Outdated
Comment thread src/Executor/Promise/Adapter/AmpFutureAdapter.php Outdated
Comment thread CHANGELOG.md Outdated
@simPod
simPod force-pushed the perf/avoid-fiber-per-amp-continuation branch from 67ab737 to 79f8304 Compare July 25, 2026 07:31
@simPod
simPod requested a review from spawnia July 25, 2026 07:36
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.

3 participants