Skip to content

Add ServerContextInterface for coroutine-safe request handling#171

Merged
koriym merged 3 commits into1.xfrom
coroutine-safe
Feb 2, 2026
Merged

Add ServerContextInterface for coroutine-safe request handling#171
koriym merged 3 commits into1.xfrom
coroutine-safe

Conversation

@koriym
Copy link
Member

@koriym koriym commented Jan 29, 2026

Summary

  • Add ServerContextInterface to abstract $_SERVER access for thread-safe operation in Swoole/RoadRunner
  • Add GlobalServerContext as default implementation for PHP-FPM
  • Update ResourceStorage to use ServerContextInterface for X_VARY handling
  • Add RepositoryLoggerInterface::reset() for long-running environments

Test plan

  • All existing tests pass
  • New GlobalServerContextTest covers the interface implementation
  • CI passes on all PHP versions (8.2-8.5)

Introduce ServerContextInterface to abstract $_SERVER access, enabling
thread-safe operation in concurrent environments like Swoole/RoadRunner.

Changes:
- Add ServerContextInterface with get() and has() methods
- Add GlobalServerContext for traditional PHP-FPM (default)
- Update ResourceStorage to use ServerContextInterface for X_VARY handling
- Add RepositoryLoggerInterface::reset() for long-running environments

Note: MobileEtagSetter is not modified (uses global state, rarely used)
@koriym
Copy link
Member Author

koriym commented Jan 29, 2026

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 29, 2026

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.

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

  • 🔍 Trigger a full review
📝 Walkthrough

Walkthrough

The PR introduces a thread-safe server context abstraction (ServerContextInterface and GlobalServerContext) for accessing $_SERVER superglobals, adds a reset() method to logger classes for long-running environments, integrates the server context into ResourceStorage to replace direct $_SERVER access, and provides associated test coverage and dependency injection bindings.

Changes

Cohort / File(s) Summary
Server Context Interface & Implementation
src/ServerContextInterface.php, src/GlobalServerContext.php
Introduces new ServerContextInterface defining thread-safe methods get(string $key): string|null and has(string $key): bool. GlobalServerContext provides a concrete implementation for traditional PHP-FPM environments using the $_SERVER superglobal, ensuring only string values are returned and missing keys are handled gracefully.
Dependency Injection Configuration
src/QueryRepositoryModule.php
Adds a new binding in QueryRepositoryModule::configure() to provide ServerContextInterface implementation as a singleton, integrating GlobalServerContext into the module's dependency graph.
Logger Reset Functionality
src/RepositoryLoggerInterface.php, src/RepositoryLogger.php
Adds reset(): void method to both interface and implementation to enable clearing accumulated logs. The reset method is documented as necessary for long-running environments (e.g., Swoole, RoadRunner) to prevent cross-request log accumulation.
Storage Integration
src/ResourceStorage.php
Introduces ServerContextInterface dependency as a constructor-promoted property and replaces direct $_SERVER access with calls to serverContext->get() and serverContext->has(). Updates serialization/deserialization logic to include the server context.
Test Coverage
tests/GlobalServerContextTest.php, tests/RepositoryLoggerTest.php, tests/ResourceRepositoryTest.php, tests/ResourceStorageTest.php
Adds comprehensive tests for GlobalServerContext behavior (get/has operations, string/non-string values), logger reset functionality, and updates existing resource storage tests to pass the new GlobalServerContext dependency.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 29.03% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: introducing ServerContextInterface for thread-safe request handling in coroutine environments, which is the primary objective of the PR.
Description check ✅ Passed The description is directly related to the changeset, providing a clear summary of the four main additions (ServerContextInterface, GlobalServerContext, ResourceStorage updates, and RepositoryLoggerInterface::reset()) with test coverage details.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch coroutine-safe

Tip

🧪 Unit Test Generation v2 is now available!

We have significantly improved our unit test generation capabilities.

To enable: Add this to your .coderabbit.yaml configuration:

reviews:
  finishing_touches:
    unit_tests:
      enabled: true

Try it out by using the @coderabbitai generate unit tests command on your code files or under ✨ Finishing Touches on the walkthrough!

Have feedback? Share your thoughts on our Discord thread!


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 and usage tips.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 29, 2026

✅ Actions performed

Review triggered.

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.

@codecov
Copy link

codecov bot commented Jan 29, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (696cbf0) to head (82fd020).
⚠️ Report is 5 commits behind head on 1.x.

Additional details and impacted files
@@             Coverage Diff             @@
##                 1.x      #171   +/-   ##
===========================================
  Coverage     100.00%   100.00%           
- Complexity       241       246    +5     
===========================================
  Files             52        53    +1     
  Lines            729       746   +17     
===========================================
+ Hits             729       746   +17     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@greptile-apps
Copy link

greptile-apps bot commented Jan 29, 2026

Greptile Overview

Greptile Summary

Adds ServerContextInterface to abstract $_SERVER access, enabling coroutine-safe operation in Swoole/RoadRunner environments while maintaining backward compatibility with PHP-FPM through GlobalServerContext.

Key Changes

  • New abstraction layer: ServerContextInterface with get() and has() methods replaces direct $_SERVER access in ResourceStorage
  • Default implementation: GlobalServerContext maintains existing behavior for PHP-FPM environments
  • Logger reset capability: RepositoryLoggerInterface::reset() prevents log accumulation in long-running processes
  • Complete migration: All $_SERVER access in ResourceStorage now goes through the interface, including X_VARY handling
  • Serialization support: ServerContextInterface properly included in __serialize() and __unserialize() methods
  • DI configuration: Bound as singleton in QueryRepositoryModule for easy override in Swoole/RoadRunner setups

Architecture

The change follows a clean abstraction pattern - users running on Swoole/RoadRunner can provide a custom request-scoped implementation of ServerContextInterface, while PHP-FPM users get the default GlobalServerContext automatically. The implementation is non-breaking and requires no changes to existing code.

Confidence Score: 5/5

  • This PR is safe to merge with minimal risk
  • Clean abstraction with comprehensive test coverage, backward compatible, and follows established patterns in the codebase
  • No files require special attention

Important Files Changed

Filename Overview
src/ServerContextInterface.php New interface added to abstract $_SERVER access for coroutine-safe request handling
src/GlobalServerContext.php Default implementation of ServerContextInterface using $_SERVER superglobal for PHP-FPM
src/ResourceStorage.php Updated to use ServerContextInterface instead of direct $_SERVER access, includes serialization support
src/QueryRepositoryModule.php Added DI binding for ServerContextInterface to GlobalServerContext in singleton scope
src/RepositoryLoggerInterface.php Added reset() method to clear logs in long-running environments

Sequence Diagram

sequenceDiagram
    participant Client
    participant ResourceStorage
    participant ServerContext as ServerContextInterface
    participant Cache as TagAwareAdapter
    
    Note over Client,Cache: Cache Key Generation with Vary Support
    
    Client->>ResourceStorage: get(uri)
    ResourceStorage->>ResourceStorage: getUriKey(uri, "ro-")
    ResourceStorage->>ServerContext: has("X_VARY")
    alt X_VARY exists
        ServerContext-->>ResourceStorage: true
        ResourceStorage->>ResourceStorage: getVary()
        ResourceStorage->>ServerContext: get("X_VARY")
        ServerContext-->>ResourceStorage: "val1,val2"
        loop for each vary value
            ResourceStorage->>ServerContext: get("X_VAL1"), get("X_VAL2")
            ServerContext-->>ResourceStorage: value
        end
        ResourceStorage->>ResourceStorage: append vary string to key
    else X_VARY not present
        ServerContext-->>ResourceStorage: false
    end
    ResourceStorage->>Cache: getItem(key)
    Cache-->>ResourceStorage: cached state
    ResourceStorage-->>Client: ResourceState|null
    
    Note over ResourceStorage,ServerContext: PHP-FPM: GlobalServerContext uses $_SERVER<br/>Swoole/RoadRunner: Custom implementation with request scope
Loading

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@tests/GlobalServerContextTest.php`:
- Around line 9-24: The tearDown currently only unsets
TEST_KEY/TEST_STRING/TEST_INT but misses restoring HTTP_USER_AGENT and X_VARY;
update GlobalServerContextTest to save original values of
$_SERVER['HTTP_USER_AGENT'] and $_SERVER['X_VARY'] in setUp (or capture the
whole $_SERVER snapshot) and then restore those specific keys in tearDown
(reassign original values if they existed, or unset if they were absent) so that
tests do not leak HTTP_USER_AGENT or X_VARY state between runs; modify the setUp
and tearDown methods in GlobalServerContextTest accordingly.
🧹 Nitpick comments (1)
src/ResourceStorage.php (1)

246-260: Trim X_VARY tokens to handle optional whitespace.

Without trimming, values like "Accept-Language, User-Agent" will look for X_ USER-AGENT and skip a vary dimension, risking cache collisions.

✅ Suggested fix
-        $varys = explode(',', $xvary);
+        $varys = explode(',', $xvary);
         $varyString = '';
         foreach ($varys as $vary) {
+            $vary = trim($vary);
+            if ($vary === '') {
+                continue;
+            }
             $phpVaryKey = sprintf('X_%s', strtoupper($vary));
             $value = $this->serverContext->get($phpVaryKey);
             if ($value !== null) {
                 $varyString .= $value;
             }
         }

- Fix test tearDown to restore HTTP_USER_AGENT and X_VARY
- Trim X_VARY tokens to handle optional whitespace
@koriym
Copy link
Member Author

koriym commented Jan 29, 2026

@coderabbitai Fixed: Test tearDown now restores HTTP_USER_AGENT and X_VARY. Added trim() to handle whitespace in X_VARY tokens.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 29, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Examine the GlobalServerContextTest.php for tearDown implementation
cat tests/GlobalServerContextTest.php

# Search for trim() usage related to X_VARY
rg -n "trim.*X_VARY|X_VARY.*trim" -A 2 -B 2

Length of output: 2397


🏁 Script executed:

#!/bin/bash
# Search for trim() usage in the source files
rg -n "trim\(" src/ -A 2 -B 2

# Also check ResourceStorage.php specifically for X_VARY handling
cat src/ResourceStorage.php

Length of output: 9935


@koriym Thank you for the update! I've verified both fixes:

Test tearDown restoration (lines 28-38 in GlobalServerContextTest.php):

  • Properly saves original values in setUp() for all test keys including HTTP_USER_AGENT and X_VARY
  • Restores original values or unsets keys in tearDown() if they didn't exist
  • Prevents test pollution across test runs

trim() for X_VARY tokens (line 257 in ResourceStorage.php):

$vary = trim($vary);
if ($vary === '') {
    continue;
}
  • Handles whitespace in comma-separated X_VARY values (e.g., "val1, val2, val3")
  • Skips empty tokens after trimming

Both improvements enhance the robustness of the implementation for production use and testing. The changes look great! 🎉

Replace unreachable null-return with assert since getVary() is only
called when has('X_VARY') is true. Add test for empty X_VARY segment.
@koriym koriym merged commit 7c0403e into 1.x Feb 2, 2026
37 checks passed
@koriym koriym deleted the coroutine-safe branch February 2, 2026 15:20
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