-
Notifications
You must be signed in to change notification settings - Fork 4.6k
Fix users events & missed publisher logic for Functions #10348
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
📝 WalkthroughWalkthroughAdds a new BrokerPool-backed resource alias Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested reviewers
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 PHPStan (2.1.17)Note: Using configuration file /phpstan.neon. If the excluded path can sometimes exist, append (?) parameters: Tip 🔌 Remote MCP (Model Context Protocol) integration is now available!Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats. ✨ Finishing Touches
🧪 Generate unit tests
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
Status, Documentation and Community
|
Security Scan Results for PRDocker Image Scan Results
Source Code Scan Results🎉 No vulnerabilities found! |
✨ Benchmark results
⚡ Benchmark Comparison
|
There was a problem hiding this 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
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (7)
src/Appwrite/Platform/Tasks/ScheduleExecutions.php (2)
46-49
: Inverted enqueue window check: schedules in-window are skipped.For items due before or at intervalEnd, we should enqueue; the current condition continues instead. This prevents any execution from being queued within the intended window.
Apply:
- if ($scheduledAt <= $intervalEnd) { - continue; - } + // Only enqueue items that fall within the next ENQUEUE_TIMER window + if ($scheduledAt > $intervalEnd) { + continue; + }
56-63
: Clamp negative “$delay” before sleeping
Clock skew or load spikes can make the computed$delay
slightly negative, causingCo::sleep()
to receive invalid values (and skewing your enqueue-delay metrics). Let’s ensure we never sleep for less than zero seconds:• File src/Appwrite/Platform/Tasks/ScheduleExecutions.php, inside
enqueueResources()
before the\go()
call- $delay = $scheduledAt->getTimestamp() - (new \DateTime())->getTimestamp(); + $delay = max(0, $scheduledAt->getTimestamp() - (new \DateTime())->getTimestamp());It might also help to add a small test asserting that under tight timing windows,
$delay
is never negative.src/Appwrite/Platform/Tasks/ScheduleFunctions.php (3)
79-83
: Use coroutine-friendly sleep to avoid blocking the reactor thread.Inside a coroutine, prefer Swoole coroutine sleep. Also ensure the import exists.
Patch within this block:
- \sleep($delay); // in seconds + Co::sleep($delay); // in secondsAnd add the import near the top:
+use Swoole\Coroutine as Co;
85-87
: Don't abort the entire batch when a single schedule is missing.Returning here stops processing remaining schedules with the same delay. Continue instead.
- if (!\array_key_exists($scheduleKey, $this->schedules)) { - return; - } + if (!\array_key_exists($scheduleKey, $this->schedules)) { + continue; + }
67-71
: Clamp $delay to zero to guard against negative waits.Boundary timing can produce negative delays; clamp to zero before sleeping.
- $delay = $executionStart - $promiseStart; // Time to wait from now until execution needs to be queued + $delay = max(0, $executionStart - $promiseStart); // Clamp to avoid negativesapp/controllers/api/account.php (2)
1718-1767
: Nit: wrong constant reference 'TYPE::EMAIL' will fatally errorWithin OAuth2 redirect session creation, factors include TYPE::EMAIL instead of the imported Type::EMAIL. This will fatal at runtime.
Apply this minimal fix:
- 'factors' => [TYPE::EMAIL, 'oauth2'], // include a special oauth2 factor to bypass MFA checks + 'factors' => [Type::EMAIL, 'oauth2'], // include a special oauth2 factor to bypass MFA checks
3918-3930
: Verify token source in phone verification updateThis action fetches the target profile by userId but verifies the token against $user->getAttribute('tokens', []) rather than $profile->getAttribute('tokens', []). If the session user differs or is empty, verification will fail or pass incorrectly.
Apply this fix:
- $verifiedToken = Auth::tokenVerify($user->getAttribute('tokens', []), Auth::TOKEN_TYPE_PHONE, $secret); + $verifiedToken = Auth::tokenVerify($profile->getAttribute('tokens', []), Auth::TOKEN_TYPE_PHONE, $secret);
🧹 Nitpick comments (12)
src/Appwrite/Platform/Tasks/ScheduleFunctions.php (1)
110-114
: Follow-up on lastEnqueueUpdate tracking.Comment notes enabling this breaks scheduling. Please track a task to properly re-enable drift correction or remove the field to avoid confusion. If needed, I can draft a minimal fix that updates it at the end of the tick and adjusts the timeFrame math accordingly.
app/cli.php (2)
212-214
: Future-proof queueForFunctions to depend on publisherFunctions.To keep the decoupling effective if/when publisher and publisherFunctions diverge, wire queueForFunctions to the new alias.
-CLI::setResource('queueForFunctions', function (Publisher $publisher) { - return new Func($publisher); -}, ['publisher']); +CLI::setResource('queueForFunctions', function (Publisher $publisherFunctions) { + return new Func($publisherFunctions); +}, ['publisherFunctions']);
191-199
: Consider adding consumerFunctions alias for symmetry (optional).If any CLI tasks ever consume from the functions pool directly, mirroring consumerFunctions keeps naming consistent with app/init/resources.php.
Proposed addition (outside this hunk):
CLI::setResource('consumerFunctions', function (BrokerPool $consumer) { return $consumer; }, ['consumer']);app/worker.php (2)
318-321
: Wire queueForFunctions to publisherFunctions for consistency.Bind queueForFunctions to the new alias so future split pools won’t require sweeping changes.
-Server::setResource('queueForFunctions', function (Publisher $publisher) { - return new Func($publisher); -}, ['publisher']); +Server::setResource('queueForFunctions', function (Publisher $publisherFunctions) { + return new Func($publisherFunctions); +}, ['publisherFunctions']);
266-280
: Optional: add consumerFunctions alias to mirror app/init.For parity with app/init/resources.php, consider:
Server::setResource('consumerFunctions', function (BrokerPool $consumer) { return $consumer; }, ['consumer']);app/init/resources.php (1)
144-146
: Bind queueForFunctions to publisherFunctions to honor the split.Small DI tweak to ensure the queue uses the dedicated functions pool if/when it diverges.
-App::setResource('queueForFunctions', function (Publisher $publisher) { - return new Func($publisher); -}, ['publisher']); +App::setResource('queueForFunctions', function (Publisher $publisherFunctions) { + return new Func($publisherFunctions); +}, ['publisherFunctions']);app/controllers/api/account.php (2)
265-267
: Also set Event.userId alongside params for consistent payloads and downstream consumersAcross many routes you correctly add setParam('userId', ...). However, Event payloads expose a top-level userId (via setUserId) that some workers/consumers rely on. Today preparePayload() includes userId separately from params. To avoid missing userId in payloads, please set both.
Example patch (apply the same pattern to other touched sites):
@@ - $queueForEvents->setParam('userId', $user->getId()); + $queueForEvents + ->setUserId($user->getId()) + ->setParam('userId', $user->getId());And where sessionId/tokenId/targetId are set, keep setParam as you already do.
If you prefer avoiding duplication, we can modify Event to fall back to params['userId'] when userId is null. Otherwise, setting both keeps behavior explicit and backward-compatible. Want me to open a small follow-up for the Event fallback?
Also applies to: 438-439, 761-765, 852-856, 983-986, 1114-1116, 1719-1723, 1763-1767, 2873-2874, 2960-2961, 3057-3058, 3143-3144, 3181-3182, 3219-3221, 3500-3503, 3633-3667, 3880-3883, 3946-3949, 4051-4051, 4161-4161, 4251-4251, 4314-4314, 4380-4381, 4505-4506, 4940-4942, 5005-5007, 5060-5063
147-153
: Nit: incorrect PHP DateTime format 'YYYY' in email variablesIn sendSessionAlert(), DateTime::format('YYYY') will literally output "YYYY". PHP uses 'Y' for a 4-digit year.
Apply this change:
- 'year' => (new \DateTime())->format('YYYY'), + 'year' => (new \DateTime())->format('Y'),app/controllers/shared/api.php (1)
666-693
: Emitting functions/webhooks/realtime from a single route-level event may limit multi-entity actionsThe shutdown block emits one event per request. For actions affecting multiple entities (e.g., bulk session delete), this can under-report events. If parity with previous behavior is desired, consider allowing per-entity emission in-route using cloned events, skipping the global emission for that request.
I can draft a small helper to clone+trigger per entity while preserving audits and usage behavior. Interested?
app/controllers/api/users.php (3)
199-200
: Attach userId to the event: good placement and minimal surface.Setting
userId
on$queueForEvents
immediately after persistence ensures route-level label interpolation (users.[userId].create
) has data at publish time. No payload is sent, which is consistent with other user mutation routes that avoid exposing PII in event payloads.If you want future maintainers to discover this intentionally minimal event envelope quickly, consider a tiny docblock noting that we only set
userId
here (and why), e.g.:-/** TODO: Remove function when we move to using utopia/platform */ +/** + * TODO: Remove function when we move to using utopia/platform + * Note: We intentionally only attach `userId` to the route Event for `users.*.create` + * to avoid sending user PII in event payloads. + */
62-75
: Add a short docblock to reflect the new parameter and intent.This helper now carries an Event dependency. A small docblock improves readability until the TODO is resolved.
Apply:
/** TODO: Remove function when we move to using utopia/platform */ +/** + * Creates a user and attaches `userId` to the route event queue for + * `users.[userId].create`. Avoids sending PII in event payloads. + * + * @param string $hash + * @param array|string $hashOptions + * @param string $userId + * @param ?string $email + * @param ?string $password + * @param ?string $phone + * @param string $name + * @param Document $project + * @param Database $dbForProject + * @param Event $queueForEvents Event publisher for route labels + * @param Hooks $hooks + * @return Document + */ function createUser(
204-239
: Consider adding an integration test to assert event emission on all 8 create routes.Given the PR goal (fixing Users.*.create events), a thin end-to-end assertion per route variant would guard against future regressions.
I can draft a small test suite that:
- hits each route with a unique ID,
- stubs the event publisher (or inspects the emitted label/params),
- asserts one event emitted with label
users.[userId].create
and paramuserId
.Would you like me to open a follow-up PR with these tests?
Also applies to: 241-276, 278-314, 315-351, 352-395, 396-432, 433-481, 483-522
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (10)
app/cli.php
(1 hunks)app/controllers/api/account.php
(3 hunks)app/controllers/api/health.php
(1 hunks)app/controllers/api/users.php
(18 hunks)app/controllers/shared/api.php
(2 hunks)app/init/resources.php
(2 hunks)app/worker.php
(1 hunks)src/Appwrite/Platform/Tasks/ScheduleBase.php
(3 hunks)src/Appwrite/Platform/Tasks/ScheduleExecutions.php
(1 hunks)src/Appwrite/Platform/Tasks/ScheduleFunctions.php
(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (5)
src/Appwrite/Platform/Tasks/ScheduleBase.php (4)
src/Appwrite/Platform/Modules/Functions/Http/Executions/Create.php (1)
action
(100-506)src/Appwrite/Platform/Tasks/ScheduleExecutions.php (1)
getSupportedResource
(19-22)src/Appwrite/Platform/Tasks/ScheduleFunctions.php (1)
getSupportedResource
(24-27)src/Appwrite/Platform/Tasks/ScheduleMessages.php (1)
getSupportedResource
(18-21)
app/controllers/api/users.php (1)
src/Appwrite/Event/Event.php (2)
Event
(10-641)setParam
(282-287)
app/controllers/api/account.php (1)
src/Appwrite/Event/Event.php (2)
Event
(10-641)setParam
(282-287)
app/controllers/api/health.php (2)
src/Appwrite/Platform/Tasks/ScheduleBase.php (1)
action
(72-110)src/Appwrite/Event/Event.php (1)
Event
(10-641)
app/controllers/shared/api.php (2)
src/Appwrite/Utopia/Response.php (1)
Response
(151-963)src/Appwrite/Event/Event.php (1)
Event
(10-641)
🔇 Additional comments (15)
src/Appwrite/Platform/Tasks/ScheduleExecutions.php (1)
33-34
: Correct broker: switch to publisherFunctions is right.Using the dedicated functions broker pool here aligns this task with the new DI and isolates function traffic from other publishers. Good change.
src/Appwrite/Platform/Tasks/ScheduleFunctions.php (1)
93-96
: Correct broker: constructing Func with publisherFunctions.Matches the new separation and keeps function enqueues on the dedicated pool. Looks good.
app/cli.php (1)
197-199
: LGTM: publisherFunctions CLI resource mirrors publisher.Good forward-compat alias to decouple functions traffic. No issues spotted.
app/worker.php (1)
254-257
: LGTM: publisherFunctions worker resource alias added.This keeps worker DI consistent with the new aliasing approach.
app/init/resources.php (2)
90-93
: LGTM: publisherFunctions alias registered.Matches the new DI shape and enables clean separation. Looks good.
105-108
: LGTM: consumerFunctions alias registered.Good to have symmetry with publisher side; no issues found.
app/controllers/api/account.php (2)
293-299
: Good wiring of users.[userId].create route event and DI of queueForEventsLabeling the route with event users.[userId].create and injecting Event $queueForEvents is the right move to restore Users.*.create emissions post-database-listener removal. Setting the userId param inside the action ensures proper pattern substitution.
Also applies to: 327-329, 438-439
606-641
: Clarify event emission scope for session deletionsThe proposed refactor correctly addresses the bug where
$session
outside the loop could be undefined or point to the last iterated session, ensuring that the finalsessionId
is explicitly captured for the “current” session within the loop.Please confirm which behavior is desired:
- Emit exactly one “users.{userId}.sessions.{sessionId}.delete” event for the current session (as identified by the matching secret), or
- Emit a delete event for each session being removed.
If you intend the former, apply the diff below. If the latter, consider triggering your event inside the loop (e.g. cloning or re-instantiating the queue per session) rather than relying on shutdown.
Apply this diff for the single-event approach:
@@ -605,7 +605,10 @@ - foreach ($sessions as $session) {/** @var Document $session */ + $eventSessionId = null; + foreach ($sessions as $session) {/** @var Document $session */ $dbForProject->deleteDocument('sessions', $session->getId()); @@ -619,6 +622,7 @@ if ($session->getAttribute('secret') == Auth::hash(Auth::$secret)) { $session->setAttribute('current', true); + $eventSessionId = $session->getId(); // If current session delete the cookies too $response @@ -639,9 +643,15 @@ $dbForProject->purgeCachedDocument('users', $user->getId()); - $queueForEvents - ->setParam('userId', $user->getId()) - ->setParam('sessionId', $session->getId()); + if ($eventSessionId !== null) { + $queueForEvents + ->setParam('userId', $user->getId()) + ->setParam('sessionId', $eventSessionId); + }Let me know which emission pattern you’d like to support so we can finalize the implementation.
src/Appwrite/Platform/Tasks/ScheduleBase.php (1)
27-31
: Verified publisherFunctions DI wiring across the applicationAll checks confirm the new
publisherFunctions
resource is registered, injected, and used correctly:• Resource registration found in
–app/worker.php
(line 254)
–app/cli.php
(line 197)
–app/init/resources.php
(line 90)• Injection into controllers confirmed in
–app/controllers/api/health.php
(line 691)• Scheduler classes consume the new pool via constructor:
–src/Appwrite/Platform/Tasks/ScheduleFunctions.php
(line 93)
–src/Appwrite/Platform/Tasks/ScheduleExecutions.php
(line 33)• No scheduler subclass still uses
$this->publisher
for enqueueing function jobsThe wiring is complete—no outstanding references to the old
publisher
resource remain.app/controllers/api/health.php (1)
690-697
: Functions queue health now uses dedicated publisherFunctions and correct queue nameSwitching to ->inject('publisherFunctions') and Event::FUNCTIONS_QUEUE_NAME aligns with the new publisher alias and keeps queue sizing accurate. No issues spotted.
app/controllers/shared/api.php (2)
394-409
: Route-level event model aligns with removing the DB event listener; ensure all routes needing events set labelsMoving event emission to route labels + queueForEvents is sound. Double-check that all endpoints relying on Users.* events (create/update/delete plus token/verification flows) have event labels post-removal of the DB listener. I noticed recoveries/verification have labels; consider adding labels for createEmailToken/createPhoneToken as well if those were previously emitted via DB listener.
I can scan the codebase and propose a list of routes without labels that still set queueForEvents payloads so you can decide case-by-case. Want me to run that?
503-509
: Usage metrics hook on DOCUMENTS_UPSERT looks goodAdding the upsert hook ensures usage metrics remain accurate after the listener refactor. No changes requested.
app/controllers/api/users.php (3)
207-207
: All 8 user-create routes consistently labeled – LGTMVerified that each of the following lines in
app/controllers/api/users.php
includes->label('event', 'users.[userId].create')ensuring uniform event taxonomy for plaintext, bcrypt, md5, argon2, sha, phpass, scrypt, and scrypt-modified variants:
- Line 207
- Line 244
- Line 281
- Line 318
- Line 355
- Line 399
- Line 436
- Line 486
No further changes needed.
233-236
: Approve DI wiring:queueForEvents
injection is consistent
Ranrg -nP --type=php "\->inject('queueForEvents')" -C1
across all modified files and confirmed the container binding name is used exactly and consistently in every route and closure. The closures correctly type-hintEvent $queueForEvents
, and all calls tocreateUser()
pass$queueForEvents
in the proper position for the updated signature.
63-75
: Signature extended to accept Event; call sites are up-to-dateThe new parameter order
( …, Document $project, Database $dbForProject, Event $queueForEvents, Hooks $hooks )
has been applied consistently in all downstream calls withinapp/controllers/api/users.php
. I verified that each invocation at lines 235, 271, 308, 345, 389, 426, 476, and 516 passes the full set of 11 arguments—including the newEvent $queueForEvents
—so there are no stale call sites remaining.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
🧹 Nitpick comments (1)
app/controllers/shared/api.php (1)
64-69
: Helpful rationale; minor wording polish (optional)The intent is clear; consider a concise phrasing to aid future readers.
/** - * This single-event based on a `Database::EVENT_DOCUMENT_CREATE` listener may look odd, but it is **intentional**. - * - * Accounts can be created in many ways beyond `createAccount` - * (anonymous, OAuth, phone, etc.), and those flows are probably not covered in event tests; so we handle this here. + * Intentionally handle user creation via a Database::EVENT_DOCUMENT_CREATE listener. + * Accounts can be created outside `createAccount` (anonymous, OAuth, phone, etc.), + * and those flows may be missed by route-based event tests; handle them here. */
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (1)
composer.lock
is excluded by!**/*.lock
📒 Files selected for processing (1)
app/controllers/shared/api.php
(5 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: Setup & Build Appwrite Image
- GitHub Check: Setup & Build Appwrite Image
- GitHub Check: scan
🔇 Additional comments (1)
app/controllers/shared/api.php (1)
32-32
: BrokerPool import verified and compatibility confirmed
- composer.lock lists
utopia-php/queue
at version 0.11.0, which providesUtopia\Queue\Broker\Pool
.- The same alias (
Pool as BrokerPool
) is already imported and used in multiple locations (e.g., ScheduleBase, Doctor, worker.php, cli.php, resources.php), ensuring consistency.- No discrepancies found in how dependencies are constructed elsewhere.
No further changes needed—approving as is.
There was a problem hiding this 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/controllers/shared/api.php (1)
418-419
: New DI injection 'publisherFunctions' — verify cross-file resource registration and usage.Good addition. Please double‑check the DI registrations so that:
publisherFunctions
is defined and bound to the functions queue brokers.- Any
queueForFunctions
resource definitions consumepublisherFunctions
(not the legacypublisher
).Run:
#!/bin/bash set -euo pipefail echo "Where is publisherFunctions registered/injected?" rg -nP --type=php -C2 "(publisherFunctions)\b" app || true echo echo "Check queueForFunctions wiring across entrypoints:" rg -nP --type=php -C3 "\b(queueForFunctions)\b" app | sed -n '1,200p'
🧹 Nitpick comments (2)
app/controllers/shared/api.php (2)
64-69
: Nit: Align the doc comment with the actual event name format.You emit
users.[userId].create
(with a path parameter) below, while the comment mentionsusers.*.create
. Consider updating to avoid confusion.- * This isolated event handling for `users.*.create` which is based on a `Database::EVENT_DOCUMENT_CREATE` listener may look odd, but it is **intentional**. + * This isolated event handling for `users.[userId].create`, which is based on a `Database::EVENT_DOCUMENT_CREATE` listener, may look odd, but it is **intentional**.If you’d like, I can also add a brief note here explaining how the event param is substituted (setParam('userId', ...)) to help future readers.
556-564
: Remove redundant from() at call-site; the listener calls from() again.You pre-apply
->from($queueForEvents)
before passing the queues into$eventDatabaseListener
, and then call->from($queueForEvents)
again inside the listener. This is harmless but noisy and could confuse readers.->on(Database::EVENT_DOCUMENT_CREATE, 'create-trigger-events', fn ($event, $document) => $eventDatabaseListener( $project, $document, $response, $queueForEventsClone->from($queueForEvents), - $queueForFunctions->from($queueForEvents), - $queueForWebhooks->from($queueForEvents), - $queueForRealtime->from($queueForEvents) + $queueForFunctions, + $queueForWebhooks, + $queueForRealtime ));
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (1)
app/controllers/shared/api.php
(5 hunks)
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: ItzNotABug
PR: appwrite/appwrite#10348
File: app/controllers/shared/api.php:546-546
Timestamp: 2025-08-22T06:23:32.002Z
Learning: The Utopia\Queue\Broker\Pool class (aliased as BrokerPool) implements both Publisher and Consumer interfaces, making it directly compatible with constructors expecting Publisher parameters like Func::__construct(protected Publisher $publisher). No wrapping is needed.
Learnt from: ItzNotABug
PR: appwrite/appwrite#10348
File: app/controllers/shared/api.php:546-546
Timestamp: 2025-08-22T06:23:32.002Z
Learning: In the Utopia Queue system, the Pool class implements both Publisher and Consumer interfaces, so BrokerPool (Pool) can be passed directly to constructors expecting Publisher parameters like Func::__construct(protected Publisher $publisher).
Learnt from: ItzNotABug
PR: appwrite/appwrite#10348
File: app/controllers/shared/api.php:546-546
Timestamp: 2025-08-22T06:23:32.002Z
Learning: In Appwrite's codebase, Utopia\Queue\Broker\Pool (aliased as BrokerPool) is a readonly class that implements both Publisher and Consumer interfaces, allowing it to be used directly in constructors expecting either interface type. This is extensively used throughout the codebase for queue operations.
📚 Learning: 2025-08-22T06:23:32.002Z
Learnt from: ItzNotABug
PR: appwrite/appwrite#10348
File: app/controllers/shared/api.php:546-546
Timestamp: 2025-08-22T06:23:32.002Z
Learning: In Appwrite's codebase, Utopia\Queue\Broker\Pool (aliased as BrokerPool) is a readonly class that implements both Publisher and Consumer interfaces, allowing it to be used directly in constructors expecting either interface type. This is extensively used throughout the codebase for queue operations.
Applied to files:
app/controllers/shared/api.php
📚 Learning: 2025-08-22T06:23:32.002Z
Learnt from: ItzNotABug
PR: appwrite/appwrite#10348
File: app/controllers/shared/api.php:546-546
Timestamp: 2025-08-22T06:23:32.002Z
Learning: The Utopia\Queue\Broker\Pool class (aliased as BrokerPool) implements both Publisher and Consumer interfaces, making it directly compatible with constructors expecting Publisher parameters like Func::__construct(protected Publisher $publisher). No wrapping is needed.
Applied to files:
app/controllers/shared/api.php
📚 Learning: 2025-08-22T06:23:32.002Z
Learnt from: ItzNotABug
PR: appwrite/appwrite#10348
File: app/controllers/shared/api.php:546-546
Timestamp: 2025-08-22T06:23:32.002Z
Learning: In the Utopia Queue system, the Pool class implements both Publisher and Consumer interfaces, so BrokerPool (Pool) can be passed directly to constructors expecting Publisher parameters like Func::__construct(protected Publisher $publisher).
Applied to files:
app/controllers/shared/api.php
🧬 Code graph analysis (1)
app/controllers/shared/api.php (2)
src/Appwrite/PubSub/Adapter/Pool.php (1)
Pool
(9-46)src/Appwrite/Platform/Tasks/ScheduleBase.php (1)
action
(72-110)
🔇 Additional comments (3)
app/controllers/shared/api.php (3)
32-32
: BrokerPool alias import is correct and necessary for the new injection.Importing
Utopia\Queue\Broker\Pool as BrokerPool
aligns with the new$publisherFunctions
DI parameter typed asBrokerPool
. No issues spotted here.
434-434
: Action closure parameterization looks consistent.
BrokerPool $publisherFunctions
matches the new injection and keeps$publisher
(events) separate from$publisherFunctions
(functions). Parameter order also tracks the inject list. LGTM.
546-547
: Approved: Valid use of BrokerPool as Publisher for FuncVerified that Appwrite\Event\Func::__construct requires a Publisher and that Utopia\Queue\Broker\Pool implements the Publisher interface (alongside Consumer). No wrapper is needed, and passing your $publisherFunctions directly is correct.
Key confirmations:
- src/Appwrite/Event/Func.php defines
public function __construct(protected Publisher $publisher)
- vendor/utopia-php/queue/src/Queue/Broker/Pool.php reads
readonly class Pool implements Publisher, Consumer
What does this PR do?
Users.*.create not fired on Cloud and also seems to have a different event handling logic.
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