Skip to content

Release idle database sessions and improve coroutine HTTP streaming - #653

Merged
binaryfire merged 23 commits into
0.4from
fix/framework-io-lifecycle
Oct 7, 2026
Merged

binaryfire merged 23 commits into
0.4from
fix/framework-io-lifecycle

Conversation

@binaryfire

@binaryfire binaryfire commented Oct 7, 2026 •

Copy link
Copy Markdown
Member

This PR lets requests return idle database sessions to the pool while waiting on an external service, and makes streamed HTTP responses deliver data incrementally. It also fixes several resource-lifetime and isolation problems exposed by those paths.

The motivating case is a request that reads from the database, waits several seconds for an API, then writes a result. That could be an AI response, a webhook, a payment service, or a file service. Holding a database connection during the wait limits concurrency even when the database itself has little work to do.

Release idle database sessions before HTTP requests

Previously, a coroutine kept its borrowed database connection until it finished. The HTTP client now returns idle database sessions before sending an outgoing request. The next query borrows a session automatically.

The PHP connection object remains owned by the request. Existing builders, query logs, callbacks and sticky read routing stay valid while the underlying PDO can return to the pool. This reuses existing database connections; it does not establish a new database connection for each request.

Release happens after request callbacks and before destination resolution or network I/O, including redirects and retries. Faked requests do not release connections, and the release check does not resolve database services or open a connection.

Active queries, transactions, open cursors and scoped foreign-key suppression keep their sessions automatically. Ordinary queries require no application changes. For other external work, or before starting child coroutines, release explicitly:

use Hypervel\Support\Facades\DB;
use Hypervel\Support\Facades\Http;

use function Hypervel\Coroutine\parallel;

$order = DB::table('orders')->find($orderId);

DB::releaseIdleConnections();

$responses = parallel([
    fn () => Http::get($inventoryUrl),
    fn () => Http::get($shippingUrl),
]);

Children own their own database connections and cannot release a connection held by their parent. Callers supplying a complete Guzzle client through setClient() also own the release boundary.

Code that deliberately depends on one physical session across an external call can pin it:

$connection = DB::connection('pgsql');

$response = $connection->withPinnedSession(function () use ($connection, $accountId, $url) {
    $connection->selectFromWriteConnection('select pg_advisory_lock(?)', [$accountId]);

    try {
        return Http::post($url);
    } finally {
        $connection->selectFromWriteConnection('select pg_advisory_unlock(?)', [$accountId]);
    }
});

DB::withPinnedSession() provides the same scope for the default connection. This is needed for temporary tables, session locks, retained raw PDOs/statements, or manual session changes spanning a release. Transactions already pin automatically. Session configurators still apply the current execution's settings before a borrowed PDO is used.

Custom drivers registered with DB::extend() retain their complete driver object until execution ends. The same applies to selectable endpoints with different drivers, database names or table prefixes. PDO drivers registered through Connection::resolverFor() can participate in early release when their logical database identity agrees.

Database measurements

These are local, pool-constrained workloads, not predictions of general SQL throughput. Measurements used an idle machine, PHP 8.4.25, Swoole 6.2.2, libcurl 8.5.0, file-backed SQLite, identical dependencies, CLI OPcache enabled, JIT disabled and GC enabled. Tables report medians from ten alternating runs; p95 columns are medians of each run's p95.

The integrated workload runs 128 requests at concurrency 32 with four database slots. Each request executes two queries separated by a real, verified-TLS HTTP call whose server waits 50 ms before returning headers. There is no explicit release call in the application path.

Variant Requests/s Database checkout p95 Session hold p95 Request p95 Client CPU/request
Before 74.6 374.7 ms 54.9 ms 427.4 ms 1,014.7 µs
Automatic release 324.8 30.9 ms 7.2 ms 98.6 ms 1,999.3 µs
Transaction pinned 74.3 375.6 ms 55.2 ms 429.3 ms 1,138.4 µs

Automatic release produced 4.35× throughput here. Throughput ranges were 74.4–75.1 requests/s before and 314.5–333.9 after. All borrowed slots were returned. Checkout time includes acquisition bookkeeping as well as waiting for a slot.

A separate experiment replaces the HTTP call with a 50 ms simulated external wait to isolate database retention. It improves from 78.1 to 598.1 requests/s, approximately 7.7×. That is a different workload from the integrated result above.

The integrated CPU increase includes repeated HTTP/TLS setup. A connection-count diagnostic observed 11–12 HTTP connections before versus 119 after, for 128 requests: releasing database slots allows larger HTTP bursts, which exceed Guzzle's three-idle-handle default for buffered requests. Configurable buffered retention is a separate dependency enhancement, tracked with a reproducible test. The streaming retention change below does not fix that buffered path.

The database ownership cost was measured separately, without HTTP or early release:

Database workload Before, CPU/request After, CPU/request Added cost
Resolve a connection 15.4 µs 24.5 µs 9.1 µs
One query 123.9 µs 136.9 µs 13.1 µs
Ten queries 886.4 µs 891.6 µs 5.1 µs
Concurrent queries with a short wait 495.9 µs 506.7 µs 10.8 µs
Transaction 529.5 µs 544.1 µs 14.6 µs

An extra 10 µs per request at 10,000 requests/s uses 0.1 CPU core, or 10% of one core. The added work is constructing and cleaning up caller-owned connection state. Reusing that state across requests would break retained builders and other caller-owned objects.

For HTTP requests that never use the database, before/after CPU and throughput ranges overlap. A separate control-adjusted probe measured the empty-context release check at about 0.18 µs. There is no database initialization on that path.

Select read endpoints with their matching metadata

Read/write connection construction could select one read endpoint for the PDO and another for its configuration metadata. The factory now selects once and uses that record for both.

Explicit ::read pools also selected a read record when the worker constructed the pool, keeping that choice for the worker lifetime. Selection now happens when a physical connection is created. Read records must agree on effective pool options, so pool behavior does not depend on whichever record was chosen first.

Release database resources promptly and safely

Disconnecting or replacing a PDO could leave a hidden reference in a discarded connection object's grammar cycle. The cleanup paths now clear those holders explicitly, including failed preparation and SQLite pool bootstrap.

Lease settlement also preserves ownership during lifecycle callbacks and clears lost resources before rollback callbacks can reconnect. Tests cover retained builders, read/write routing, nested pins, custom drivers, failed acquisition, reconnects and coroutine cleanup.

Preserve reconnects made by connection listeners

A ConnectionEstablished listener can reconnect before the original PDO resolver returns. Returning the earlier PDO would overwrite the replacement session. The resolver now returns the logical connection's current PDO after notifying listeners. Tests cover both write and read resolution, including a replacement read connection that remains lazy until the outer resolver resumes.

Keep transaction callbacks isolated between coroutines

Copying coroutine context could share mutable transaction records with a child. The child could then alter its parent's records or run callbacks belonging to the parent.

Pending, committed and current transaction records now live together in a non-copyable DatabaseTransactionState. Testbench explicitly transfers the same state across setup, test and teardown; normal child coroutines do not inherit transaction ownership.

Deliver HTTP streams incrementally

The PHP stream-wrapper path can batch body data instead of exposing each available chunk. Hooked coroutine requests now use a pull-driven cURL streaming body. Reads return available bytes immediately, and a bounded buffer pauses network reads when the consumer falls behind. There is no background producer coroutine.

$response = Http::withOptions(['stream' => true])->get($url);

try {
    foreach ($response->jsonLines() as $event) {
        processEvent($event);
    }
} finally {
    $response->close();
}

Each active response owns its transfer. Completion, close, cancellation, errors and abandoned consumption release it. Named connections reuse idle transports without retaining request callbacks, credentials or cookies. Proxy tunnel reuse requires the same ownership signature.

For streaming requests, timeout bounds the header phase. When cURL negotiates authentication, this includes waiting for the first body bytes or transfer completion, since even a successful status can be an intermediate response. read_timeout bounds idle gaps during headers and body reads; its default is 60 seconds, and zero disables that idle limit. Long streams can continue beyond the header timeout. Custom handlers/clients retain their existing ownership, and the PHP-stream fallback remains available for supported options that require it.

Bounded connection reuse

Named streaming connections retain up to 32 idle transports per worker, created only when needed. This does not limit active requests. Larger bursts can still open additional connections, which are discarded when the idle cache is full.

Ten alternating paired measurements used 256 verified-TLS requests at concurrency 32, unpaced 4 KiB responses, and the same transport with only the retention bound changed:

Idle retention Requests/s CPU/request New connections after warmup Retained process descriptors
3 525.5 1,731.8 µs 232 18
32 1,262.2 621.3 µs 0 105

On this Linux build, each retained transport accounts for a socket and both ends of a wakeup pipe. The higher bound trades idle resources for less connection setup. Descriptor counts returned to their starting values after cleanup. Runs using the final default also verified reuse at concurrency 32 and bounded retention at concurrency 128.

Swoole's native curl_multi_select() currently has a separate readiness defect that can delay a streamed event or completion by up to one second. It appeared in paced measurements. The regression is captured, and post-fix measurements are tracked in docs/todo.md; this PR adds no polling or shorter-wait workaround. No general performance claim is made for the buffering change while that runtime issue remains.

Release discarded streaming handles without cyclic collection

Guzzle 7 can discard a cURL handle without clearing its callbacks. A receive callback holding that same handle creates a cycle that retains native and request resources until garbage collection. The callback now holds a weak reference; the active transfer remains the owner. The abandoned-response test verifies that both the response body and native handle are released with cyclic collection disabled.

Preserve streaming callback order and cancellation

A small response can finish before the handler exposes its headers. Its trailer callback must still run after on_headers, rather than before it. Completion now preserves that order and delivers the original Guzzle callback arguments.

Pre-header retries retain the original callbacks. Callback failures retain their response where applicable, and coroutine cancellation passes through Guzzle and routing exception conversion unchanged. Statistics are reported once at the handler-return boundary.

Cancel opted-in response producers when their client disconnects

An iterable response can now cancel its producer when the client connection closes:

return response()->eventStream(function () use ($events) {
    yield from $events;
})->cancelOnDisconnect();

Cancellation applies only while producing that response. Application close callbacks still run, and unrelated requests or later termination work are unaffected. The connection map retains every active producer, including pipelined HTTP/1 responses. Tests verify that cancellation interrupts a silent upstream wait and releases the transfer.

Existing Swoole releases do not notify PHP when one HTTP/2 stream is reset while its connection remains open. A quiet producer detects that case on a later failed write or operation completion/timeout. Whole-connection closes are handled now; the separate stream-cancel event is tracked as a future runtime integration.

Avoid repeated coroutine-context lookups

Container scoped resolution, auth defaults, Inertia state, static instances and Blade rendering now retrieve context values once instead of checking and retrieving them separately. Null-as-absent behavior, false/zero values and lazy fallbacks are preserved. Blade does not touch an uninitialized fallback property when context already contains the value.

Expose file and directory checks through the filesystem contract

Filesystem now declares fileExists() and directoryExists(). Concrete adapters already support these checks; contract consumers and custom implementations can now rely on them without capability probes. exists() still accepts either a file or a directory.

$disk = Storage::disk('s3');

$disk->fileExists('reports/latest.json');
$disk->directoryExists('reports');

Custom contract implementations must provide both methods. The Storage facade and porting documentation reflect the contract.

Trace existence checks on all Sentry filesystem decorators

Existence-check instrumentation moves to the base filesystem decorator. Plain and cloud contract implementations now receive the same tracing as adapters, without duplicate instrumentation methods on the adapter decorator.

Expose object property schemas without serialization

ObjectType::getProperties() returns the original named Type objects. Consumers can inspect or reuse them without serializing the schema or bypassing protected state.

use Hypervel\JsonSchema\JsonSchema;

$schema = JsonSchema::object([
    'name' => JsonSchema::string()->required(),
]);

$properties = $schema->getProperties();

Property-array annotations also accept integer keys produced by PHP's normalization of numeric strings. Schema serialization is unchanged.

Cache recursive trait membership

ClassMetadataCache::usesTrait() resolves direct, nested and inherited traits once per class:

use App\Models\Order;
use Hypervel\Database\Eloquent\SoftDeletes;
use Hypervel\Support\ClassMetadataCache;

$usesSoftDeletes = ClassMetadataCache::usesTrait(Order::class, SoftDeletes::class);

The cache stores class metadata rather than every queried class/trait pair, so negative lookups do not keep adding entries. Existing static cleanup clears it between tests.

Watch directory arrivals and skill paths

Fswatch event mapping now recognizes watched roots, their ancestors and recursive descendant directories. Linux watches include the shallow ancestors needed to notice an initially missing root. Glob filtering and sibling exclusions remain intact, without broadening macOS watch operands.

resources/skills/** is included in the default watch paths. The docs explain custom skill paths, conservative reloads on directory arrivals, and Linux fswatch event loss around missing roots and directory moves. Polling drivers remain the appropriate option for those workflows; no rescanning or process-recycling workaround is added.

Restore Testbench environment values through their original repository

Flushing the dotenv repository while masking APP_ENV discarded the writer ownership needed to remove values loaded by an earlier application. Scoped environment helpers could also replace the repository before a WithEnv restorer ran.

The redundant flushes are removed. WithEnv captures the repository that owns its value and restores the raw prior value through that repository. Nested class/method restorers run in reverse order, preserving external environment values and preventing leakage between tests.

Verification and reproducibility

Formatting, source/type static analysis, the framework suite, Testbench package mode and the package-consumer suite pass locally. Focused streaming checks also cover the supported Guzzle 7 and 8 branches. Tests exercise real loopback I/O, database pool contention, cancellation, isolation and cleanup; performance thresholds are not part of CI.

tests/Benchmarks/Database and tests/Benchmarks/HttpTransport include standalone harnesses and reproduction instructions. They report actual concurrency, latency, CPU, connection reuse, pool checkout/hold times, memory, descriptors and GC. Known dependency regressions have explicit tests and tracked follow-ups rather than production workarounds.

Note

Add database session leases, coroutine cURL streaming, and response cancellation

  • Adds ConnectionLease so each coroutine keeps a stable logical PdoConnection while the pool borrows and returns physical PDO sessions. Idle sessions are released automatically around outbound HTTP requests via new middleware in PendingRequest.php, and Connection::withPinnedSession() keeps a session attached for temporary tables or advisory locks. Leases activate only when no connection extension is configured and all read/write endpoints resolve to the same logical database identity.
  • Adds CurlStreamingHandler with a new CurlStreamingBody PSR-7 stream: supported stream requests use coroutine-native cURL chunking with backpressure instead of the buffered fallback sink middleware.
  • Adds opt-in client-disconnect cancellation for IterableStreamedResponse via cancelOnDisconnect(). ResponseCancellation in src/server/src/ResponseCancellation.php registers producer coroutines and cancels them when the connection closes; supported in coroutine base mode and selected process dispatch modes.
  • Rewrites FswatchDriver target resolution to watch shallow ancestor directories so root-arrival events and missing watch roots are observed without recursing from the project root.
  • Adds fileExists and directoryExists to the Filesystem contract; moves the Sentry wrappers from FilesystemAdapterDecorator to FilesystemDecorator, and exists() now covers both files and directories.
  • Risk: behavioral changes — read records with conflicting effective pool options now throw InvalidArgumentException in DatabasePool::readPoolConfig; stream requests with restricted destination policies are rejected only when native streaming is unsupported; custom Filesystem implementations must add fileExists/directoryExists to satisfy the widened contract in Filesystem.php.

Macroscope summarized 6d1f614.

Group the public implementation into seven review checkpoints with explicit implementer and reviewer responsibilities. Allow dependencies to move forward while requiring complete files, meaningful tests and signoff before advancing. Preserve copy-first porting and permit coherent whole-file commits with detailed rationale and validation.

Build incremental HTTP streaming against the current framework handler boundaries and existing tests. Remove the unrelated transport-worktree prerequisite while preserving cancellation, resource ownership and performance acceptance requirements.

Validation: reviewed both plan updates and ran git diff --check. Documentation-only change; no source tests or benchmarks were run.
Keep coroutine-owned concrete connections stable while allowing idle physical sessions to return to the pool before long external waits. Add releaseIdleConnections and scoped session pinning, preserving retained builders, sticky routing, query state, transactions, cursors and event callbacks.

Keep config-first extensions and endpoints with different logical identities under whole-connection ownership. Select read endpoints per physical generation, preserve selected configuration metadata, settle leases exactly once, and clear hidden PDO holders promptly on disconnect and failed replacement. Preserve the current owner during terminal callbacks and forget lost resources before rollback callbacks can reconnect.

Cover ownership, read/write routing, custom drivers, session configuration, failure recovery and teardown with regression tests. Document extension and pinning behavior and add an independently runnable database lifecycle benchmark. Benchmarks remain required before opening the framework PR; reviewed checkpoints may proceed before the idle measurement window.

Validation of the complete checkpoint: formatting and source/type PHPStan passed; 40,181 framework tests, 632 Testbench tests and 6 package-consumer tests passed with expected service skips.
Group pending, committed and current transaction records in one non-copyable DatabaseTransactionState. Child coroutines acquire independent transaction ownership instead of sharing parent records and running parent callbacks prematurely or twice.

Preserve transaction callback extension points while retrieving related state together. Keep the intentional Testbench setup-to-test transfer explicit through manager copy methods and a tests-only non-coroutine context setter, so normal child context propagation cannot inherit transactions.

Add regressions for interleaved parent and child callbacks and explicit lifecycle transfer with nested transactions. Validation of the complete checkpoint passed formatting, source/type PHPStan, 40,181 framework tests, 632 Testbench tests and 6 package-consumer tests with expected service skips.
Retrieve scoped container instances, auth defaults, Inertia state, static instances and Blade context values once instead of repeating has/get lookups on request paths.

Preserve null-as-absent behavior, false and zero scoped values, identity-based scoped removal and lazy fallback evaluation. In particular, Blade must not read an uninitialized fallback property when coroutine context already supplies the path.

Existing behavioral coverage verifies the supported values and scoped resolution semantics. The complete checkpoint passed formatting, source/type PHPStan, 40,181 framework tests, 632 Testbench tests and 6 package-consumer tests with expected service skips.
Use a pull-driven cURL transport for streamed requests inside hooked
coroutines. Each active response owns its transfer and applies backpressure
while the caller consumes buffered bytes. Named connections retain at most
three idle transports, matched by proxy ownership and replaced in least
recently used order. Keep custom clients and handlers, PHP-stream fallback,
destination policies, middleware and supported Guzzle 7/8 behavior intact.

Separate the response-header deadline from idle read timeouts, preserve
received responses on timeout and callback failure, and retain native
transfer statistics. Settle transfers on completion, close, cancellation
and abandonment without keeping request callbacks in worker-owned caches.

Add opt-in cancellation for iterable response production when a client
connection closes. Track every active producer, including pipelined HTTP/1
responses, and compose cancellation with application close callbacks only
in supported server modes. Preserve cancellation through Guzzle and routing
exception conversion. Document the existing quiet HTTP/2 stream-reset limit
and expose fluent event-stream typing without narrowing public signatures.

Validation: full composer fix passed, including 40,237 framework tests,
632 Testbench tests, six dogfood tests, PHPStan and formatting. Focused
minimum-version Guzzle 7 coverage passed 75 cases; the original Guzzle 8
dependencies were restored. Controlled performance benchmarks remain a
separate prerequisite before opening the framework PR.
Specify pull-driven streaming, bounded exact-signature idle reuse, timeout
phases, Guzzle compatibility and transfer cleanup in the active port plan.
Keep disconnect registration scoped to response production and distinguish
whole-connection cancellation from the missing native HTTP/2 reset event.

Record the verified stable-runtime limitation accurately and retain the
pre-PR performance acceptance requirements. The framework changes remain
independent of the later AI package implementation.
Declare fileExists() and directoryExists() on the shared contract while preserving the file-or-directory behavior of exists(). Existing adapters and pooled/scoped implementations already provide both operations; update the in-memory fixture and remove the obsolete read-through analysis suppression.

Move Sentry instrumentation to the base filesystem decorator so plain and cloud contract implementations receive the same tracing as adapters. Regenerate the Storage facade annotations and document the required methods for custom implementations.

Validation: filesystem cache fixtures, Sentry storage integration and facade tests pass; formatting, full PHPStan and the full framework suite pass.
Add ObjectType::getProperties() so schema consumers can inspect the original Type objects without serializing them or bypassing protected state. Preserve property names, object identity and empty-object behavior.

Correct property-array annotations across the factory, contract and static API to include integer keys produced by PHP numeric-string normalization. Document the accessor without changing schema serialization.

Validation: focused object-schema tests, formatting, full PHPStan and the full framework suite pass.
Add ClassMetadataCache::usesTrait() using the existing reflection cache. Resolve direct, nested and inherited traits once per queried class, then answer membership checks from that complete set.

Keep worker-lifetime keys bounded by classes rather than arbitrary class-and-trait lookup pairs, so negative lookups do not grow the cache. Clear the new metadata through the existing flushState() test-cleanup registration and avoid introducing a reverse dependency on Support helpers.

Validation: direct, nested, inherited, absent-trait and cache-reset coverage passes, together with formatting, full PHPStan and the full framework suite.
Watch resources/skills by default. Map native events for exact roots, their ancestors and recursive descendant directories so directory arrivals can trigger reloads even when native events omit newly created files. Exact-file watches use their parent as the arrival root and do not match nested directories.

On Linux, retain explicit missing-root operands and add shallow ancestors through the first existing directory. Preserve canonical and literal mappings, glob filtering, sibling exclusions and the existing process grouping; do not broaden Darwin operands.

Document conservative directory-arrival restarts and Linux fswatch limitations for initially absent roots and directory moves or renames. Recommend existing polling drivers for those workflows instead of adding rescans, latency tuning or process recycling. Record the resulting watcher requirements in the active plan.

Validation: scripted mapping and real directory-arrival/subsequent-edit tests pass. Formatting, full PHPStan and all 183 Watcher tests pass after review corrections; the preceding full framework suite also passes. Native macOS missing-root behavior has not been verified.
Remove redundant repository flushes around APP_ENV masking. Environment adapters already read the live globals; replacing the repository discarded the immutable writer ownership needed to forget values loaded by earlier application bootstraps, leaking state into later tests.

Have WithEnv capture its originating repository and raw prior value so cleanup survives scoped environment helpers replacing the active repository. Restore nested class and method attributes in reverse order while preserving external-value protection and leaving other lifecycle callbacks unchanged.

Extend existing tests for scoped-helper composition, class/method attributes sharing a key in both environment-loading modes, and standalone application cleanup. The previously failing application-then-migration test sequence now passes.

Validation: formatting and full PHPStan pass; the framework suite passes with 40,246 tests, package-mode Testbench with 635 tests, and dogfood with 6 tests. Existing service-dependent skips remain.
Keep CURLMOPT_MAXCONNECTS set to one on each streaming multi handle, but remove the dead failure branch around this fixed supported option and its unused exception import. Connection-cache ownership and limits are unchanged.

Validation: formatting, full PHPStan and the full framework suite pass, including the HTTP streaming coverage.
Return the current execution's idle database sessions to their pools before
real framework HTTP requests. Run after application request callbacks and
fake selection, before destination resolution and transport I/O, so redirects
and retries also release sessions borrowed by callbacks.

Make the resolver operation static and delegate to it directly from the
database manager. This avoids resolving database services or opening a
connection merely to release sessions. Existing transactions, cursors,
scoped foreign-key suppression and explicit pins retain their sessions.

Document automatic release, lazy reacquisition, named/default session pins,
manual release before coroutine fan-out and caller-supplied Guzzle clients.
Explain the session-dependent compatibility cases in the porting guide.

Verify real requests against a silent loopback origin with a one-slot pool,
sibling database access, callbacks, retries, redirects and pin preservation.
Formatting, both full PHPStan checks, the full framework suite, Testbench
package mode and dogfood pass. Performance acceptance remains separate.
Pause native receives at BufferStream's high-water mark instead of after
every body chunk. Resume only after draining the buffer, clearing the shared
pause flag before resuming because cURL may synchronously fill and pause the
buffer again. Reads continue returning available bytes immediately.

Defer trailer callbacks when a transfer completes before response exposure.
Deliver their original Guzzle arguments after successful header processing
and before statistics, preserving response-bearing errors and cancellation.
Restore the original trailer callback during pre-header retries and clear
pending arguments during cleanup. Keep post-exposure completion on Guzzle's
existing callback path.

Extend streaming tests for bounded buffering, small and streamed trailers,
header rejection, callback failure, retry and cancellation. Add synchronized
reproductions for the native select readiness defect, concurrent PHP-stream
header retention and Guzzle's shared fallback deadline. Keep the approved
dependency-version skips and upstream-fix TODOs, without runtime workarounds.
Remove deprecated no-op cURL close calls from the affected tests.

Focused callback and streaming checks pass with Guzzle 7 and 8. Formatting,
both full PHPStan checks, 40,255 framework tests, 635 Testbench package tests
and six dogfood tests pass, with configured skips. The first full run hit the
known Swoole #6280 manager shutdown race; the unchanged suite passed on rerun.
High-water performance acceptance remains pending controlled benchmarks and
the separate native select dependency decision.
Extend the database lifecycle harness with independently sized pools,
optional checkout/hold/request latency measurements and a real HTTP wait.
The HTTP scenario exercises automatic release without a manual release call;
transaction mode provides the pinned comparison. Keep instrumentation
optional so CPU and allocation measurements avoid its sample-array cost.

Add a separate verified-TLS loopback origin and HTTP transport harness for
cold and warm requests, paced streams, slow consumers, named transport reuse,
buffered requests and bytewise baseline readers. Report first-event latency,
throughput, client CPU, actual concurrency, native connection identities,
heap, RSS, descriptors and garbage collection. Keep connection identities
cumulative across samples and explain measurement bookkeeping costs.

Document alternating paired runs with identical dependencies and runtime
settings, an idle machine, raw reports outside the repository and no timing
thresholds in CI. Keep simulated waits distinct from integrated HTTP results.
Update the active port plan for default database release, callback ordering,
dependency regressions and the remaining performance acceptance work.

Harness syntax and command-line help checks pass, as do repository formatting,
static analysis and the framework/Testbench/dogfood suites. These commits do
not claim completion of the remaining controlled benchmarks or PR readiness.
Raise the lazy named streaming retention bound from three to 32. Bursts above the old bound repeatedly discarded reusable TLS connections, adding substantial setup cost. Preserve the existing ownership, exact proxy-signature matching and least-recently-used eviction; active requests remain uncapped and unnamed streams retain no idle transports.

Extend the existing direct/proxy integration test through the configured retention bound, preserving credential and cookie isolation assertions and verifying reuse and eviction. Document the bound in the HTTP client guide and its measured descriptor cost in the benchmark guide. Correct the streaming buffering description and record the separate Guzzle buffered-retention dependency decision in the active plan.

Validation: formatting and both full PHPStan configurations pass. The HTTP suite passes with 1,053 tests and 3,143 assertions, retaining 11 existing skips. Verified-TLS runs with the actual default reused all 32 warm connections without further connections and returned descriptors to baseline after cleanup. A concurrency-128 stability run retained the same bounded idle resources; the known Swoole select timing defect remains a separate native dependency.
Add a synchronized real-client regression for two bursts of four buffered requests through one named connection. Guzzle retains only three idle easy handles, so the second burst unnecessarily opens a fifth connection. Keep the owner-requested skip until configurable retention is available and adopted; no dependency workaround is introduced.

Track both Guzzle-dependent skips and the post-fix Swoole native-select regression and performance checks in docs/todo.md. Update the active plan to allow the framework PR before the native fix while withholding unqualified buffering performance claims.

Validation: the final default-configuration test failed its connection-count assertion in 20 of 20 runs, then passed in 20 of 20 runs with only a temporary vendor retention increase from three to four. The complete test file passed with that change and with the skip restored. Vendor was restored byte-for-byte. Formatting and full static analysis passed; the HTTP suite passed with 1,054 tests and 12 intentional or existing skips.
Exclude the imported, unported AI SDK documentation and the AI implementation plan from this framework change. Preserve both on feature/ai for the separate package port. Runtime code, framework documentation, regression tests and dependency follow-ups remain included.
@coderabbitai

coderabbitai Bot commented Oct 7, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration
  • Configuration used: Repository: hypervel/components/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 9eb27593-d67d-4004-abcd-e4bd985c6a0f

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@binaryfire

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Oct 7, 2026 •

Copy link
Copy Markdown
⚠️ Action not completed

Review skipped: 104 files exceed the limit of 100.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@binaryfire

Copy link
Copy Markdown
Member Author

@cubic-dev-ai review

@cubic-dev-ai

cubic-dev-ai Bot commented Oct 7, 2026

Copy link
Copy Markdown

@cubic-dev-ai review

@binaryfire cubic can't start this review because your workspace has reached its free monthly review limit. cubic has reviewed 124,545 of the 120,000 allowed lines of code this month. Reviews resume on 10 October 2026 (in 3 days). Paid plans include much higher monthly review limits. Upgrade now to resume reviews.

To help optimise your usage, you can tune cubic to get the most out of your usage limits:

Learn more →

@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

Release idle database sessions and stream coroutine HTTP responses

🐞 Bug fix ✨ Enhancement 🧪 Tests 📝 Documentation 🕐 40+ Minutes

Grey Divider

AI Description

• Return idle database sessions before outgoing HTTP calls without losing request-owned connection
 state.
• Deliver coroutine HTTP streams incrementally with bounded buffering and disconnect cancellation.
• Fix transaction isolation and resource cleanup; add regression tests and reproducible benchmarks.
Diagram

graph TD
  R["Request coroutine"] --> H["HTTP middleware"] --> S["Streaming handler"] --> B["Response body"]
  H --> L["Logical lease"] --> P[("Database pool")]
  R --> O["Response producer"] --> C["Disconnect cancellation"]
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Require explicit database release
  • ➕ Avoids an automatic HTTP-stack release boundary.
  • ➖ Existing requests continue holding scarce sessions during external waits.
  • ➖ Callers must identify every request, retry, and redirect boundary.
2. Keep only Guzzle PHP-stream handling
  • ➕ Avoids maintaining a separate cURL streaming implementation.
  • ➖ Preserves delayed incremental delivery in hooked coroutines.
  • ➖ Cannot cover the same cURL destination-pinning path.

Recommendation: Keep automatic release and native streaming with a PHP-stream fallback: together they improve existing callers without changing ordinary query APIs. Review lease settlement and callback ownership closely; the documented Swoole readiness issue remains a separate follow-up.

Files changed (104) +6330 / -620

Enhancement (31) +1683 / -229
CoroutineContext.phpAdd test-only non-coroutine context setter +15/-0

Add test-only non-coroutine context setter

• Lets tests explicitly transfer owned state into non-coroutine storage without copying it into child coroutines.

src/context/src/CoroutineContext.php

Filesystem.phpDeclare specific existence checks +11/-1

Declare specific existence checks

• Adds fileExists and directoryExists alongside the general exists check.

src/contracts/src/Filesystem/Filesystem.php

JsonSchema.phpAccept normalized numeric property keys +1/-1

Accept normalized numeric property keys

• Allows integer object-property keys produced by PHP numeric-string normalization.

src/contracts/src/JsonSchema/JsonSchema.php

ResponseFactory.phpExpose event-stream response typing +3/-0

Expose event-stream response typing

• Documents iterable event-stream results so consumers can configure disconnect cancellation.

src/contracts/src/Routing/ResponseFactory.php

Connection.phpPin sessions during active operations +140/-92

Pin sessions during active operations

• Adds explicit scoped pinning and protects queries, streaming queries, transactions, and foreign-key suppression from early release.

src/database/src/Connection.php

ConnectionResolver.phpSeparate logical owners from physical leases +77/-40

Separate logical owners from physical leases

• Retains caller-owned connections, exposes a context-only idle-release check, and settles current owners on cleanup.

src/database/src/ConnectionResolver.php

DatabaseManager.phpExpose idle-session release +12/-3

Expose idle-session release

• Adds releaseIdleConnections and clarifies pooled disconnect semantics.

src/database/src/DatabaseManager.php

ConnectionLease.phpIntroduce physical-session leases +157/-0

Introduce physical-session leases

• Keeps a logical connection stable while borrowing, returning, reconnecting, or discarding pooled PDO sessions.

src/database/src/Pool/ConnectionLease.php

PooledConnection.phpSeparate driver resources from borrower state +195/-76

Separate driver resources from borrower state

• Attaches logical leases, selects read endpoints on physical creation, and settles resources through lifecycle callbacks.

src/database/src/Pool/PooledConnection.php

ReadThroughFilesystem.phpAlign read-through existence checks +1/-1

Align read-through existence checks

• Adjusts the adapter for the expanded filesystem contract.

src/filesystem/src/ReadThroughFilesystem.php

Server.phpPass response stream identity through bridge +2/-2

Pass response stream identity through bridge

• Adjusts response sending to carry stream identity for cancellation handling.

src/grpc/src/Server/Server.php

ResponseBridge.phpRegister opted-in producers while streaming +19/-1

Register opted-in producers while streaming

• Checks client writability and registers active iterable producers only during content generation.

src/http-server/src/ResponseBridge.php

Server.phpPass HTTP response stream identity +1/-0

Pass HTTP response stream identity

• Supplies stream identity to the response bridge.

src/http-server/src/Server.php

CurlStreamingBody.phpImplement pull-driven bounded response body +565/-0

Implement pull-driven bounded response body

• Reads available bytes incrementally and owns timeout, callback, completion, cancellation, and cleanup behavior.

src/http/src/Client/CurlStreamingBody.php

CurlStreamingConnection.phpIsolate native transport per active stream +26/-0

Isolate native transport per active stream

• Wraps an exclusive cURL multi handle that can be retained for safe idle reuse.

src/http/src/Client/CurlStreamingConnection.php

CurlStreamingHandler.phpRoute hooked-coroutine streams through cURL +214/-0

Route hooked-coroutine streams through cURL

• Selects native streaming where supported and retains a bounded number of named idle transports.

src/http/src/Client/CurlStreamingHandler.php

Factory.phpEnable streaming for named connections +5/-1

Enable streaming for named connections

• Wraps named connection handlers with native streaming and bounded idle retention.

src/http/src/Client/Factory.php

PendingRequest.phpRelease idle sessions before real HTTP sends +30/-2

Release idle sessions before real HTTP sends

• Places release after fakes and before destination resolution, enables streaming, and preserves cancellation across exception conversion.

src/http/src/Client/PendingRequest.php

IterableStreamedResponse.phpAdd opt-in disconnect cancellation +20/-0

Add opt-in disconnect cancellation

• Lets an iterable response request producer cancellation when its client connection closes.

src/http/src/IterableStreamedResponse.php

JsonSchema.phpAccept normalized numeric schema keys +1/-1

Accept normalized numeric schema keys

• Updates object-schema property annotations to permit integer keys.

src/json-schema/src/JsonSchema.php

JsonSchemaTypeFactory.phpAlign factory property annotations +1/-1

Align factory property annotations

• Allows integer and string object-property keys in factory typing.

src/json-schema/src/JsonSchemaTypeFactory.php

ObjectType.phpExpose original object property schemas +12/-2

Expose original object property schemas

• Adds getProperties and broadens key annotations without changing serialization.

src/json-schema/src/Types/ObjectType.php

ClassMetadataCache.phpCache recursive trait membership +42/-0

Cache recursive trait membership

• Resolves direct, nested, and inherited traits once per class and clears the cache during cleanup.

src/reflection/src/ClassMetadataCache.php

ResponseCancellation.phpTrack active producers by connection +79/-0

Track active producers by connection

• Registers opted-in coroutines and cancels active producers on connection close without affecting later work.

src/server/src/ResponseCancellation.php

Server.phpWire producer cancellation into close events +25/-1

Wire producer cancellation into close events

• Installs close handling in compatible server modes while preserving application callbacks.

src/server/src/Server.php

DB.phpExpose session lifecycle through DB facade +2/-0

Expose session lifecycle through DB facade

• Documents idle release and scoped pinning facade methods.

src/support/src/Facades/DB.php

Response.phpReflect iterable event-stream typing +1/-1

Reflect iterable event-stream typing

• Updates facade annotations for disconnect-capable responses.

src/support/src/Facades/Response.php

Storage.phpExpose specific existence checks +2/-2

Expose specific existence checks

• Updates Storage facade declarations for fileExists and directoryExists.

src/support/src/Facades/Storage.php

Server.phpAlign WebSocket response bridge call +1/-1

Align WebSocket response bridge call

• Adjusts response-bridge invocation for the added stream identity argument.

src/websocket-server/src/Server.php

Connection.phpType scoped session pinning +1/-0

Type scoped session pinning

• Adds static-analysis typing for the connection pinning API.

types/Database/Connection.php

ResponseFactory.phpType disconnect-capable responses +22/-0

Type disconnect-capable responses

• Adds static-analysis declarations for iterable and event-stream response APIs.

types/Routing/ResponseFactory.php

Bug fix (14) +450 / -201
ManagesTransactions.phpPreserve rollback-callback reconnects +3/-2

Preserve rollback-callback reconnects

• Forgets failed driver resources before resetting transaction state so callbacks cannot lose newly opened resources.

src/database/src/Concerns/ManagesTransactions.php

ConnectionFactory.phpConstruct lease-backed connections with matching metadata +32/-0

Construct lease-backed connections with matching metadata

• Creates resolver-backed logical connections and selects read endpoint configuration once for both metadata and PDO.

src/database/src/Connectors/ConnectionFactory.php

DatabaseTransactionState.phpOwn transaction records in non-copyable state +41/-0

Own transaction records in non-copyable state

• Groups pending, committed, and current transaction records into one execution-owned context object.

src/database/src/DatabaseTransactionState.php

DatabaseTransactionsManager.phpIsolate transaction callbacks between coroutines +64/-109

Isolate transaction callbacks between coroutines

• Moves transaction records into non-copyable execution state so children cannot mutate or invoke parent callbacks.

src/database/src/DatabaseTransactionsManager.php

PdoConnection.phpTransfer and clear PDO resources safely +129/-40

Transfer and clear PDO resources safely

• Adds physical-resource attach/detach operations, pins open cursors, and clears discarded temporary holders.

src/database/src/PdoConnection.php

DatabasePool.phpChoose safe lease and read-pool policies +78/-11

Choose safe lease and read-pool policies

• Enables early release only for compatible logical identities and validates effective options across read records.

src/database/src/Pool/DatabasePool.php

InteractsWithTestCaseLifecycle.phpPreserve test transaction ownership +2/-1

Preserve test transaction ownership

• Transfers transaction state explicitly across test lifecycle boundaries.

src/foundation/src/Testing/Concerns/InteractsWithTestCaseLifecycle.php

RunTestsInCoroutine.phpTransfer test-owned transaction state +1/-0

Transfer test-owned transaction state

• Preserves transaction ownership despite non-copyable child context.

src/foundation/src/Testing/Concerns/RunTestsInCoroutine.php

ResponseFactory.phpPreserve streaming cancellation +11/-1

Preserve streaming cancellation

• Prevents event-stream and download factories from reporting or wrapping coroutine cancellation.

src/routing/src/ResponseFactory.php

FilesystemDecorator.phpTrace existence checks for all filesystem types +17/-1

Trace existence checks for all filesystem types

• Instruments fileExists and directoryExists at the common decorator level.

src/sentry/src/Features/Storage/FilesystemDecorator.php

WithEnv.phpRestore environment through its owning repository +7/-6

Restore environment through its owning repository

• Captures the original dotenv repository and raw value despite subsequent repository replacement.

src/testbench/src/Attributes/WithEnv.php

CreatesApplication.phpRestore nested environment values in reverse order +1/-4

Restore nested environment values in reverse order

• Removes ownership-losing repository flushes and reverses attribute restorers.

src/testbench/src/Concerns/CreatesApplication.php

Application.phpStop discarding dotenv writer ownership +0/-3

Stop discarding dotenv writer ownership

• Removes redundant repository cleanup that could prevent earlier application values from being removed.

src/testbench/src/Foundation/Application.php

FswatchDriver.phpRecognize directory arrivals and missing roots +64/-23

Recognize directory arrivals and missing roots

• Matches relevant directory events and adds shallow Linux ancestor watches without broadening macOS operands.

src/watcher/src/Driver/FswatchDriver.php

Refactor (7) +21 / -43
AuthManager.phpAvoid duplicate guard-context lookup +2/-5

Avoid duplicate guard-context lookup

• Reads the coroutine's default guard once before falling back to configuration.

src/auth/src/AuthManager.php

PasswordBrokerManager.phpAvoid duplicate broker-context lookups +4/-2

Avoid duplicate broker-context lookups

• Retrieves coroutine-scoped broker defaults once while preserving fallback behavior.

src/auth/src/Passwords/PasswordBrokerManager.php

Container.phpResolve scoped instances with fewer context reads +9/-5

Resolve scoped instances with fewer context reads

• Reuses retrieved scoped instances for resolution and extension without changing cache ownership.

src/container/src/Container.php

InertiaState.phpAvoid repeated Inertia context reads +3/-3

Avoid repeated Inertia context reads

• Retrieves coroutine-scoped state once while preserving fallback semantics.

src/inertia/src/InertiaState.php

FilesystemAdapterDecorator.phpRemove duplicate existence tracing +0/-16

Remove duplicate existence tracing

• Drops adapter-only instrumentation now supplied by the shared decorator.

src/sentry/src/Features/Storage/FilesystemAdapterDecorator.php

StaticInstance.phpRead static coroutine instances once +1/-5

Read static coroutine instances once

• Eliminates redundant context checks without changing fallback behavior.

src/support/src/Traits/StaticInstance.php

BladeCompiler.phpAvoid duplicate Blade context checks +2/-7

Avoid duplicate Blade context checks

• Uses single reads for path and echo format while preserving fallback safety.

src/view/src/Compilers/BladeCompiler.php

Tests (37) +3963 / -139
AfterEachTestSubscriber.phpClear response cancellation between tests +1/-0

Clear response cancellation between tests

• Flushes active-producer tracking during test cleanup.

src/testing/src/PHPUnit/AfterEachTestSubscriber.php

benchmark.phpAdd database lifecycle benchmark +305/-0

Add database lifecycle benchmark

• Measures pooled query, transaction, release, and optional HTTP workloads with concurrency and resource metrics.

tests/Benchmarks/Database/benchmark.php

server.phpProvide benchmark HTTP origin +63/-0

Provide benchmark HTTP origin

• Supplies controlled TLS response timing and payloads for transport measurements.

tests/Benchmarks/HttpTransport/Fixtures/server.php

benchmark.phpAdd concurrent transport benchmark +239/-0

Add concurrent transport benchmark

• Reports throughput, latency, CPU, and resource behavior under configurable concurrent HTTP traffic.

tests/Benchmarks/HttpTransport/benchmark.php

ArrayFilesystem.phpImplement expanded filesystem fixture contract +17/-1

Implement expanded filesystem fixture contract

• Adds separate file and directory existence behavior to the in-memory fixture.

tests/Cache/Fixtures/ArrayFilesystem.php

ConnectionResolverTest.phpUpdate resolver ownership assertions +22/-20

Update resolver ownership assertions

• Adapts terminal release, reuse, and failure tests to logical owners and physical leases.

tests/Database/ConnectionResolverTest.php

DatabaseConnectionFactoryTest.phpVerify matching read endpoint metadata +40/-0

Verify matching read endpoint metadata

• Asserts selected read PDO configuration and connection metadata agree.

tests/Database/DatabaseConnectionFactoryTest.php

DatabaseConnectionLeaseLifecycleTest.phpTest lease settlement and callbacks +153/-0

Test lease settlement and callbacks

• Covers terminal callbacks, repeated early release, purges, and connection replacement.

tests/Database/DatabaseConnectionLeaseLifecycleTest.php

DatabaseConnectionLeaseTest.phpExercise early release across database and HTTP work +600/-0

Exercise early release across database and HTTP work

• Tests builders, contention, callbacks, routing, pins, cursors, custom drivers, reconnects, and failures.

tests/Database/DatabaseConnectionLeaseTest.php

DatabasePdoConnectionTest.phpTest PDO replacement and failed-resource cleanup +85/-1

Test PDO replacement and failed-resource cleanup

• Checks failed preparation, physical-handle transfer, and rollback-callback reconnects.

tests/Database/DatabasePdoConnectionTest.php

DatabaseReadPoolTest.phpTest read endpoint selection +132/-0

Test read endpoint selection

• Checks creation and reconnect selection, uniform pool options, and in-memory SQLite rejection.

tests/Database/DatabaseReadPoolTest.php

DatabaseTransactionsManagerTest.phpVerify transaction state isolation +93/-0

Verify transaction state isolation

• Confirms child coroutines cannot capture parent callbacks while test lifecycle transfer preserves ownership.

tests/Database/DatabaseTransactionsManagerTest.php

PoolManagerTest.phpAdjust read-pool expectations +3/-1

Adjust read-pool expectations

• Aligns pool tests with deferred read-record selection and effective options.

tests/Database/PoolManagerTest.php

CurlStreamingHandlerTest.phpTest native streaming transport ownership +531/-0

Test native streaming transport ownership

• Covers callbacks, authentication, retries, cancellation, slow consumers, deadlines, and cleanup.

tests/Http/Client/CurlStreamingHandlerTest.php

PublicDestinationPolicyTest.phpAdjust destination-pinning assertions +25/-42

Adjust destination-pinning assertions

• Keeps host and proxy pinning checks aligned with the streaming-capable cURL path.

tests/Http/Client/Destinations/PublicDestinationPolicyTest.php

concurrent-stream-deadlines.phpProvide concurrent timeout fixture +93/-0

Provide concurrent timeout fixture

• Supplies controlled responses for PHP-stream deadline regression tests.

tests/Http/Fixtures/concurrent-stream-deadlines.php

concurrent-stream-headers.phpProvide concurrent header fixture +82/-0

Provide concurrent header fixture

• Supplies independently paced headers for streaming concurrency tests.

tests/Http/Fixtures/concurrent-stream-headers.php

streaming-server.phpExtend streaming response fixture +80/-4

Extend streaming response fixture

• Adds timing and response cases for incremental-delivery tests.

tests/Http/Fixtures/streaming-server.php

HttpClientDestinationPolicyTest.phpExercise pinned destinations with native streams +31/-11

Exercise pinned destinations with native streams

• Extends direct, redirect, and proxy policy checks to streaming requests.

tests/Http/HttpClientDestinationPolicyTest.php

HttpClientStreamingTest.phpCover incremental streaming and cancellation +417/-12

Cover incremental streaming and cancellation

• Tests chunk arrival, deadlines, trailers, reuse, fallback, cross-coroutine consumption, and silent waits.

tests/Http/HttpClientStreamingTest.php

HttpConnectionTest.phpTrack buffered connection reuse regression +64/-0

Track buffered connection reuse regression

• Adds a concurrent named-connection regression case for upstream idle-handle retention.

tests/Http/HttpConnectionTest.php

PackageMetadataTest.phpVerify HTTP dependencies +4/-0

Verify HTTP dependencies

• Asserts the new coroutine and engine package dependencies.

tests/Http/PackageMetadataTest.php

disconnect-server.phpProvide disconnect test server +102/-0

Provide disconnect test server

• Runs streaming producers and silent upstream waits for client-close integration tests.

tests/HttpServer/Fixtures/disconnect-server.php

PackageMetadataTest.phpVerify HTTP-server dependencies +1/-1

Verify HTTP-server dependencies

• Aligns package assertions with the new server dependency.

tests/HttpServer/PackageMetadataTest.php

ResponseBridgeTest.phpTest producer registration scope +130/-0

Test producer registration scope

• Checks multiple streams, already-closed clients, and cleanup before later work.

tests/HttpServer/ResponseBridgeTest.php

ResponseCancellationTest.phpTest disconnect-driven interruption +225/-0

Test disconnect-driven interruption

• Verifies whole-connection close interrupts silent upstream work and captures the HTTP/2 reset limitation.

tests/HttpServer/ResponseCancellationTest.php

PooledConnectionTest.phpCheck pooled-session cleanup +15/-4

Check pooled-session cleanup

• Updates lease-aware checks and verifies unused shared SQLite resources close promptly.

tests/Integration/Database/PooledConnectionTest.php

ConnectionEstablishedTest.phpVerify connection-established ownership +17/-6

Verify connection-established ownership

• Checks physical-generation notifications against the owning logical connection.

tests/Integration/Database/Sqlite/ConnectionEstablishedTest.php

ObjectTypeTest.phpTest direct object-property inspection +11/-0

Test direct object-property inspection

• Confirms original schema objects are returned and normalized numeric keys remain supported.

tests/JsonSchema/ObjectTypeTest.php

ResponseFactoryTest.phpTest streaming cancellation propagation +38/-0

Test streaming cancellation propagation

• Ensures response factories neither report nor wrap coroutine cancellation.

tests/Routing/ResponseFactoryTest.php

StorageIntegrationTest.phpTest existence tracing on plain filesystems +35/-0

Test existence tracing on plain filesystems

• Verifies base-decorator instrumentation reaches contract implementations.

tests/Sentry/Features/StorageIntegrationTest.php

ServerTest.phpTest close-hook installation +72/-1

Test close-hook installation

• Checks supported server modes, automatic close registration, and callback preservation.

tests/Server/ServerTest.php

ClassMetadataCacheTest.phpTest recursive trait caching +29/-0

Test recursive trait caching

• Covers inherited and nested traits, negative lookups, and cache flushing.

tests/Support/ClassMetadataCacheTest.php

WithEnvTest.phpTest original-repository restoration +31/-0

Test original-repository restoration

• Covers raw prior values and restoration after repository replacement.

tests/Testbench/Attributes/WithEnvTest.php

ApplicationTest.phpCheck dotenv ownership across applications +4/-1

Check dotenv ownership across applications

• Verifies environment loading and cleanup do not leak values.

tests/Testbench/Foundation/ApplicationTest.php

TestCaseTest.phpCheck nested environment restoration +8/-3

Check nested environment restoration

• Tests ordering of class and method environment overrides.

tests/Testbench/TestCaseTest.php

FswatchDriverTest.phpTest directory arrivals and boundaries +165/-31

Test directory arrivals and boundaries

• Exercises recursive roots, missing directories, ancestor watches, and sibling exclusions.

tests/Watcher/Driver/FswatchDriverTest.php

Documentation (12) +209 / -8
todo.mdTrack transport and runtime follow-ups +10/-0

Track transport and runtime follow-ups

• Records known Swoole streaming and HTTP/2 cancellation limitations, Guzzle-dependent tests, and AI/MCP integration work.

docs/todo.md

README.mdReference database lifecycle guidance +1/-0

Reference database lifecycle guidance

• Points package readers to guidance on releasing and pinning database sessions.

src/database/README.md

database.mdDocument releasing and pinning connections +58/-2

Document releasing and pinning connections

• Explains automatic release, explicit pinning, read-endpoint selection, and custom-driver ownership.

src/docs/database.md

filesystem.mdDocument specific existence checks +4/-2

Document specific existence checks

• Explains fileExists and directoryExists alongside exists.

src/docs/filesystem.md

http-client.mdDocument HTTP release and streaming semantics +14/-4

Document HTTP release and streaming semantics

• Covers database release boundaries, streaming timeouts, transport reuse, and PHP-stream fallback limitations.

src/docs/http-client.md

json-schema.mdDocument object property inspection +6/-0

Document object property inspection

• Shows how to retrieve named Type objects without serializing a schema.

src/docs/json-schema.md

porting-from-laravel.mdNote filesystem contract additions +4/-0

Note filesystem contract additions

• Calls out the required methods for custom filesystem implementations.

src/docs/porting-from-laravel.md

responses.mdDocument disconnect-aware streamed responses +18/-0

Document disconnect-aware streamed responses

• Explains opt-in cancellation scope and the HTTP/2 stream-reset limitation.

src/docs/responses.md

watcher.mdDocument skill watches and event limitations +7/-0

Document skill watches and event limitations

• Explains default skill paths, directory-triggered reloads, and Linux missing-root or move limitations.

src/docs/watcher.md

README.mdAdvertise filesystem existence methods +2/-0

Advertise filesystem existence methods

• Reflects specific file and directory checks available through the filesystem contract.

src/filesystem/README.md

README.mdDocument database lifecycle measurements +39/-0

Document database lifecycle measurements

• Provides repeatable pool-contention, automatic-release, CPU, and cleanup comparison instructions.

tests/Benchmarks/Database/README.md

README.mdDocument paired transport benchmarks +46/-0

Document paired transport benchmarks

• Explains comparisons of streaming reuse, buffering, latency, CPU, and descriptor retention.

tests/Benchmarks/HttpTransport/README.md

Other (3) +4 / -0
composer.jsonDeclare server cancellation dependency +1/-0

Declare server cancellation dependency

• Adds the direct package dependency needed for response cancellation.

src/http-server/composer.json

composer.jsonDeclare coroutine streaming dependencies +2/-0

Declare coroutine streaming dependencies

• Adds direct coroutine and engine package dependencies.

src/http/composer.json

watcher.phpWatch default skill directory +1/-0

Watch default skill directory

• Adds resources/skills to default watch paths.

src/watcher/config/watcher.php

@qodo-free-for-open-source-projects

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider

Great, no issues found!

Qodo reviewed your code and found no material issues that require review

Grey Divider

Tip of the day
💡 Did you know, you can route each severity your way: inline, summary, both, or drop

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread src/http/src/Client/CurlStreamingHandler.php
Comment thread src/database/src/Pool/DatabasePool.php Outdated
Comment thread src/http/src/Client/CurlStreamingBody.php
Comment thread src/database/src/Pool/ConnectionLease.php
Include the effective driver when deciding whether selectable read or
write records can share a logical connection across session leases.
Different drivers need their own connection class and grammar even when
the database and table prefix match.

Resolve the current logical PDO after publishing ConnectionEstablished.
A listener may reconnect during publication; returning the earlier PDO
would otherwise overwrite its replacement. Cover both write and read
resolution, including a replacement read PDO that remains lazy until
the outer resolver resumes.

Extend the identity tests so each case varies only its selected role,
and verify that listener reconnects retain and return one pool slot.
Clarify that connections and their builders belong to the coroutine
that resolved them and must not be passed to another coroutine.

Validated with formatting, full static analysis, and the database and
database integration suites. The reconnect regressions fail against the
previous implementation and pass with this change.
Keep a weak reference to the native handle in the receive callback.
Guzzle 7 can discard a handle without clearing its callbacks, so a strong
capture retained the handle, request and native resources until cyclic
garbage collection. The active transfer continues to own the handle;
the callback only dereferences it when pausing at the buffer limit.

Extend the abandoned-response test to check native handle lifetime with
cyclic collection disabled. Observe the real factory through a small
decorator so the test itself does not retain callback-bearing options.
The regression fails on Guzzle 7 before the change and passes on both
supported Guzzle majors afterwards.

Document that native cURL authentication negotiation can delay response
exposure until body bytes arrive or the transfer completes, and that
the request timeout covers this wait. A successful status alone cannot
identify the final response during POST authentication negotiation.

Validated with formatting, full static analysis, the HTTP client suite,
and the streaming-handler tests on Guzzle 7.15.2 and Guzzle 8.2.
@binaryfire
binaryfire merged commit feba3cc into 0.4 Oct 7, 2026
51 checks passed
Comment thread src/database/src/Pool/ConnectionLease.php
Comment thread src/database/src/ConnectionResolver.php
Comment thread src/database/src/Pool/DatabasePool.php
Comment thread src/database/src/Pool/ConnectionLease.php
Comment thread src/server/src/ResponseCancellation.php
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