Conversation
📝 WalkthroughWalkthroughBatch processing for event-driven function lookups was increased from 30 to 100. Query ordering was changed from ascending by function name to ascending by the internal sequence field. The listing query now selects only Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Pre-merge checks and finishing touches❌ Failed checks (2 warnings)
✅ Passed checks (1 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
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. Comment |
Security Scan Results for PRDocker Image Scan Results
Source Code Scan Results🎉 No vulnerabilities found! |
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (1)
src/Appwrite/Platform/Workers/Functions.php (1)
151-154: Clarify the comment about caching.The comment "get variables subqueries cached" is misleading. This code fetches the full function document (including variables) from the database—it's not necessarily leveraging a cache.
Consider updating the comment to be more accurate:
🔎 Suggested comment clarification
- /** - * get variables subqueries cached - */ + /** + * Fetch full function document including variables for execution + */ $function = $dbForProject->getDocument('functions', $function->getId());
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/Appwrite/Platform/Workers/Functions.php
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-11-12T04:07:12.576Z
Learnt from: abnegate
Repo: appwrite/appwrite PR: 10800
File: src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Bulk/Delete.php:153-154
Timestamp: 2025-11-12T04:07:12.576Z
Learning: In Appwrite's event queue system, `queueForRealtime`, `queueForFunctions`, and `queueForWebhooks` are copied from `queueForEvents`. Therefore, when resetting event queues in transaction staging paths, only `$queueForEvents->reset()` needs to be called in most cases. The other queues only require explicit reset when they are triggered in a loop.
Applied to files:
src/Appwrite/Platform/Workers/Functions.php
📚 Learning: 2025-10-23T08:06:38.889Z
Learnt from: abnegate
Repo: appwrite/appwrite PR: 10546
File: src/Appwrite/Platform/Workers/Migrations.php:144-148
Timestamp: 2025-10-23T08:06:38.889Z
Learning: In the Appwrite codebase, migration workers receive already-validated data from queued jobs. Query validation using Query::parseQueries() happens at the API endpoint level (with try-catch for QueryException) before jobs are queued, so workers in src/Appwrite/Platform/Workers/Migrations.php don't need redundant validation.
Applied to files:
src/Appwrite/Platform/Workers/Functions.php
🧬 Code graph analysis (1)
src/Appwrite/Platform/Workers/Functions.php (1)
src/Appwrite/Databases/TransactionState.php (1)
getDocument(42-83)
⏰ 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). (5)
- GitHub Check: Setup & Build Appwrite Image
- GitHub Check: Linter
- GitHub Check: Setup & Build Appwrite Image
- GitHub Check: CodeQL
- GitHub Check: scan
🔇 Additional comments (3)
src/Appwrite/Platform/Workers/Functions.php (3)
125-126: LGTM! Batch limit increase is appropriate.Increasing the batch limit from 30 to 100 will reduce the number of database round-trips when processing many functions, improving overall throughput.
130-130: Selective field fetch optimization is well-implemented.Fetching only
$idandeventsfields here avoids loading variable subqueries for functions that won't match the event filter. The full document is retrieved later (line 154) only for functions that will actually execute.
133-133: The ordering by$sequenceis intentional and aligns with function execution order handling documented in the repository history. Using$sequence(internal document creation order) ensures deterministic execution when multiple functions subscribe to the same events, which is more appropriate than name-based ordering.
✨ Benchmark results
⚡ Benchmark Comparison
|
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (1)
src/Appwrite/Platform/Workers/Functions.php (1)
152-156: Critical: N+1 query problem from per-function re-fetch.Re-fetching each function individually inside the loop creates a classic N+1 query problem. With the increased batch size of 100, this could result in 100 additional database queries per batch iteration, significantly degrading performance.
🔎 Recommended solutions
Option 1: Remove selective fetch and fetch all data initially
$functions = $dbForProject->find('functions', [ - Query::select(['$id', 'events']), // Skip variables subqueries Query::contains('events', $events), Query::limit($limit), Query::offset($offset), Query::orderAsc('$sequence'), ]); // ... inside loop ... foreach ($functions as $function) { if ($isResourceBlocked($project, RESOURCE_TYPE_FUNCTIONS, $function->getId())) { Console::log('Function ' . $function->getId() . ' is blocked, skipping execution.'); continue; } - /** - * get variables subqueries cached - */ - $function = $dbForProject->getDocument('functions', $function->getId()); - Console::success('Iterating function: ' . $function->getAttribute('name'));Option 2: Batch re-fetch after filtering (if selective fetch is necessary)
+ // Collect function IDs after filtering + $functionIds = []; foreach ($functions as $function) { if (!array_intersect($events, $function->getAttribute('events', []))) { continue; } if ($isResourceBlocked($project, RESOURCE_TYPE_FUNCTIONS, $function->getId())) { Console::log('Function ' . $function->getId() . ' is blocked, skipping execution.'); continue; } + $functionIds[] = $function->getId(); + } + + // Batch fetch all needed functions at once + if (!empty($functionIds)) { + $fullFunctions = $dbForProject->find('functions', [ + Query::equal('$id', $functionIds), + Query::limit(count($functionIds)) + ]); + + foreach ($fullFunctions as $function) { Console::success('Iterating function: ' . $function->getAttribute('name')); // ... rest of execution logicOption 1 is preferred unless there's strong evidence that the selective fetch provides significant performance benefits that outweigh the N+1 query cost.
🧹 Nitpick comments (1)
src/Appwrite/Platform/Workers/Functions.php (1)
143-145: Remove redundant event intersection check.The
array_intersectcheck appears redundant since line 131 already filters functions usingQuery::contains('events', $events). If the database query is working correctly, all returned functions should already have at least one matching event.🔎 Proposed fix to remove redundant check
foreach ($functions as $function) { - if (!array_intersect($events, $function->getAttribute('events', []))) { - continue; - } - if ($isResourceBlocked($project, RESOURCE_TYPE_FUNCTIONS, $function->getId())) {If this check is intentionally defensive (e.g., to handle edge cases where the database query might not filter correctly), please add a comment explaining why it's necessary.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/Appwrite/Platform/Workers/Functions.php
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-08-11T10:32:38.142Z
Learnt from: abnegate
Repo: appwrite/appwrite PR: 10297
File: app/controllers/api/users.php:649-657
Timestamp: 2025-08-11T10:32:38.142Z
Learning: In Appwrite's utopia-php/database (version 0.77.* and later), the database layer internally handles filter separation for count operations. When using `$dbForProject->count()` within a `skipFilters` closure, there's no need to manually separate filter queries using `Query::groupByType($queries)['filters']` as the database handles this automatically.
Applied to files:
src/Appwrite/Platform/Workers/Functions.php
🧬 Code graph analysis (1)
src/Appwrite/Platform/Workers/Functions.php (2)
src/Appwrite/Platform/Modules/Projects/Http/Projects/XList.php (1)
find(163-197)src/Appwrite/Databases/TransactionState.php (1)
getDocument(42-83)
⏰ 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 (2)
src/Appwrite/Platform/Workers/Functions.php (2)
134-134: Good improvement: ordering by$sequence.Ordering by
$sequenceprovides a more deterministic and stable sort order compared to alphabetical ordering byname, especially since function names can be changed by users.
131-131: No action needed.Query::contains('events', $events)correctly matches functions where theeventsarray contains any of the values in the$eventsarray, which is the intended behavior for this change.
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
Checklist