Skip to content

Refactor: use Coroutine context for database and cache functions#10895

Merged
abnegate merged 4 commits into1.8.xfrom
dat-957
Dec 5, 2025
Merged

Refactor: use Coroutine context for database and cache functions#10895
abnegate merged 4 commits into1.8.xfrom
dat-957

Conversation

@ArnabChatterjee20k
Copy link
Copy Markdown
Member

What does this PR do?

(Provide a description of what this PR does and why it's needed.)

Test Plan

(Write your test plan here. If you changed any code, please provide us with clear instructions on how you verified your changes work. Screenshots may also be helpful.)

Related PRs and Issues

  • (Related PR or issue)

Checklist

  • Have you read the Contributing Guidelines on issues?
  • If the PR includes a change to an API's metadata (desc, label, params, etc.), does it also include updated API specs and example docs?

@github-actions
Copy link
Copy Markdown

github-actions bot commented Dec 3, 2025

Security Scan Results for PR

Docker Image Scan Results

Package Version Vulnerability Severity
imagemagick 7.1.2.3-r0 CVE-2025-62171 HIGH
imagemagick-c++ 7.1.2.3-r0 CVE-2025-62171 HIGH
imagemagick-dev 7.1.2.3-r0 CVE-2025-62171 HIGH
imagemagick-heic 7.1.2.3-r0 CVE-2025-62171 HIGH
imagemagick-jpeg 7.1.2.3-r0 CVE-2025-62171 HIGH
imagemagick-jxl 7.1.2.3-r0 CVE-2025-62171 HIGH
imagemagick-libs 7.1.2.3-r0 CVE-2025-62171 HIGH
imagemagick-openexr 7.1.2.3-r0 CVE-2025-62171 HIGH
imagemagick-webp 7.1.2.3-r0 CVE-2025-62171 HIGH
libecpg 17.6-r0 CVE-2025-12818 HIGH
libecpg-dev 17.6-r0 CVE-2025-12818 HIGH
libpng 1.6.47-r0 CVE-2025-64720 HIGH
libpng 1.6.47-r0 CVE-2025-65018 HIGH
libpng-dev 1.6.47-r0 CVE-2025-64720 HIGH
libpng-dev 1.6.47-r0 CVE-2025-65018 HIGH
libpq 17.6-r0 CVE-2025-12818 HIGH
libpq-dev 17.6-r0 CVE-2025-12818 HIGH
libxml2 2.13.8-r0 CVE-2025-49794 CRITICAL
libxml2 2.13.8-r0 CVE-2025-49796 CRITICAL
libxml2 2.13.8-r0 CVE-2025-49795 HIGH
libxml2 2.13.8-r0 CVE-2025-6021 HIGH
postgresql17-dev 17.6-r0 CVE-2025-12818 HIGH
github.com/containerd/containerd/v2 v2.0.2 CVE-2024-25621 HIGH
golang.org/x/crypto v0.31.0 CVE-2025-22869 HIGH
golang.org/x/oauth2 v0.24.0 CVE-2025-22868 HIGH
stdlib 1.22.10 CVE-2025-47907 HIGH
stdlib 1.22.10 CVE-2025-58183 HIGH
stdlib 1.22.10 CVE-2025-58186 HIGH
stdlib 1.22.10 CVE-2025-58187 HIGH
stdlib 1.22.10 CVE-2025-61729 HIGH

Source Code Scan Results

🎉 No vulnerabilities found!

@github-actions
Copy link
Copy Markdown

github-actions bot commented Dec 3, 2025

✨ Benchmark results

  • Requests per second: 1,209
  • Requests with 200 status code: 217,606
  • P99 latency: 0.160524071

⚡ Benchmark Comparison

Metric This PR Latest version
RPS 1,209 1,272
200 217,606 228,964
P99 0.160524071 0.160067932

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Dec 3, 2025

📝 Walkthrough

Walkthrough

Replaces module-level static/global caches in app/realtime.php with per-coroutine context caching via Swoole\Coroutine::getContext(). The functions getConsoleDB, getProjectDB, getCache, getRedis, getTimelimit, getRealtime, and getTelemetry now read and write cached values on the coroutine context (keys include dbForPlatform, dbForProject indexed by sequence, cache, redis, timelimit, realtime, and telemetry). getProjectDB now returns getConsoleDB() when the project parameter is empty or "console". The Swoole\Coroutine class is imported and global $register usage is retained only after context retrieval where required.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

  • Confirm each function consistently uses Coroutine::getContext() and the intended context keys (dbForPlatform, dbForProject[$sequence], cache, redis, timelimit, realtime, telemetry).
  • Verify getProjectDB short-circuits to getConsoleDB() without skipping required initialization or side effects.
  • Check global $register is only used after context retrieval and no static/global caches remain.
  • Ensure correct import/use of Swoole\Coroutine and that getTimelimit signature and default parameters match callers.

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description check ⚠️ Warning The description is empty except for the template skeleton; it contains no actual information about the changes, test plan, or related issues. Provide a meaningful description explaining what was changed, why it was necessary, how to test it, and any related issues or PRs.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: refactoring database and cache functions to use Swoole Coroutine context instead of static variables.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch dat-957

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.

Copy link
Copy Markdown
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: 2

🧹 Nitpick comments (1)
app/realtime.php (1)

82-99: Consider reordering the empty/console check before the cache lookup.

The cache lookup at line 88 calls $project->getSequence() before checking if the project is empty or console at line 97. Moving the short-circuit check earlier would avoid unnecessary cache operations for console/empty projects.

     $ctx = Coroutine::getContext();

-    if (!isset($ctx['getProjectDB'])) {
-        $ctx['getProjectDB'] = [];
-    }
-
-    if (isset($ctx['getProjectDB'][$project->getSequence()])) {
-        return $ctx['getProjectDB'][$project->getSequence()];
-    }
-
-    global $register;
-
-    /** @var Group $pools */
-    $pools = $register->get('pools');
-
     if ($project->isEmpty() || $project->getId() === 'console') {
         return getConsoleDB();
     }
+
+    if (!isset($ctx['getProjectDB'])) {
+        $ctx['getProjectDB'] = [];
+    }
+
+    if (isset($ctx['getProjectDB'][$project->getSequence()])) {
+        return $ctx['getProjectDB'][$project->getSequence()];
+    }
+
+    global $register;
+
+    /** @var Group $pools */
+    $pools = $register->get('pools');
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 379b85b and 5878a82.

📒 Files selected for processing (1)
  • app/realtime.php (6 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Benchmark
  • GitHub Check: Setup & Build Appwrite Image
  • GitHub Check: scan
🔇 Additional comments (3)
app/realtime.php (3)

53-76: LGTM!

The coroutine context caching pattern is correctly implemented: context retrieval, cache check, lazy initialization, and storage in context before return.


136-158: LGTM!

The coroutine context caching is correctly implemented with proper cache key usage.


161-183: LGTM!

The coroutine context caching is correctly implemented. The Redis connection object is appropriately cached per-coroutine.

Copy link
Copy Markdown
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: 0

♻️ Duplicate comments (1)
app/realtime.php (1)

185-195: Key coroutine cache for getTimelimit by (key, limit, seconds) to avoid cross‑contamination.

getTimelimit() now accepts and uses $key, $limit, and $seconds when constructing TimeLimitRedis, which fixes the earlier “parameters ignored” bug. However, the coroutine cache always uses a single 'timelimit' entry, so the first call in a coroutine determines the configuration for all subsequent calls, even if different arguments are passed (e.g. if another caller or resource uses a different key/limit/window in the same coroutine).

To keep instances correctly scoped to their configuration while still caching per coroutine, cache by a composite context key derived from the arguments:

 function getTimelimit(string $key = "", int $limit = 0, int $seconds = 1): TimeLimitRedis
 {
     $ctx = Coroutine::getContext();
 
-    if (isset($ctx['timelimit'])) {
-        return $ctx['timelimit'];
-    }
-
-    return $ctx['timelimit'] = new TimeLimitRedis($key, $limit, $seconds, getRedis());
+    $cacheKey = "timelimit:{$key}:{$limit}:{$seconds}";
+
+    if (isset($ctx[$cacheKey])) {
+        return $ctx[$cacheKey];
+    }
+
+    return $ctx[$cacheKey] = new TimeLimitRedis($key, $limit, $seconds, getRedis());
 }

This preserves the new signature and avoids different abuse‑limit configurations unintentionally sharing a single TimeLimitRedis instance within a coroutine.

🧹 Nitpick comments (1)
app/realtime.php (1)

198-208: Clarify unused $workerId in getTelemetry (and minor note on getRealtime).

getRealtime()’s coroutine‑context cache via $ctx['realtime'] is fine, and the global $realtime = getRealtime(); keeps the single instance used throughout this file.

In getTelemetry(int $workerId), the $workerId parameter is currently unused, which is what PHPMD flags. If that’s intentional (e.g. placeholder for a future adapter that differentiates by worker), it would help static analysis and reader clarity to either:

  • Rename it to $_workerId to explicitly mark it unused, or
  • Add a short docblock comment noting that it’s unused by the current NoTelemetry implementation but kept for API compatibility.

Example:

-function getTelemetry(int $workerId): Utopia\Telemetry\Adapter
+function getTelemetry(int $_workerId): Utopia\Telemetry\Adapter
 {
     $ctx = Coroutine::getContext();

Also applies to: 211-222

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c4cc859 and da1285b.

📒 Files selected for processing (1)
  • app/realtime.php (6 hunks)
🧰 Additional context used
🪛 PHPMD (2.15.0)
app/realtime.php

212-212: Avoid unused parameters such as '$workerId'. (undefined)

(UnusedFormalParameter)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Setup & Build Appwrite Image
  • GitHub Check: Setup & Build Appwrite Image
  • GitHub Check: scan
🔇 Additional comments (3)
app/realtime.php (3)

54-75: Per‑coroutine console DB caching looks correct.

Using Coroutine::getContext() with a single dbForPlatform entry per coroutine and deferring the global $register lookup until after the cache check is a clean refactor from the old static cache. No behavioral issues spotted here.


80-132: Project DB coroutine context cache is consistent and preserves existing behavior.

Initializing $ctx['dbForProject'] as a per‑coroutine map keyed by getSequence() and short‑circuiting console/empty projects to getConsoleDB() keeps the previous semantics while making instances coroutine‑local. This looks good and avoids extra DSN parsing for the console project.


137-157: Cache and Redis factories match the new coroutine‑context pattern.

Both getCache() and getRedis() now correctly reuse instances within a coroutine via $ctx['cache'] / $ctx['redis'], while avoiding $register/env work on the hot path when already cached. The refactor is consistent with the DB helpers and doesn’t introduce new behavioral changes.

Also applies to: 161-182

@abnegate abnegate merged commit 549570a into 1.8.x Dec 5, 2025
43 checks passed
@abnegate abnegate deleted the dat-957 branch December 5, 2025 09:59
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