Skip to content

Migration cleanup#10955

Merged
abnegate merged 10 commits into1.8.xfrom
migration-cleanup
Dec 16, 2025
Merged

Migration cleanup#10955
abnegate merged 10 commits into1.8.xfrom
migration-cleanup

Conversation

@fogelito
Copy link
Copy Markdown
Contributor

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?

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Dec 14, 2025

📝 Walkthrough

Walkthrough

Made several properties in src/Appwrite/Platform/Workers/Migrations.php nullable (dbForProject, dbForPlatform, deviceForMigrations, deviceForFiles, project) and initialized plan to an empty array. logError’s docblock/type was changed to nullable and defaulted to null. action() now wraps processing in a try/finally to clear many object properties (databases, devices, project, logError, plan, sourceReport), nulls transfer-related locals, and calls gc_collect_cycles(). processMigration finally path nulls transfer/source/destination. Error logging messages were expanded to include prefixed "Message:", "File:", and "Line:" details. A new protected method handleCSVExportComplete(Document $project, Document $migration, Mail $queueForMails, Realtime $queueForRealtime): void was added and wired for CSV export completion. Credential endpoint handling was hardened to tolerate missing keys by using null-coalescing checks when comparing to 'http://localhost/v1'. Additional null-checked cleanup was added to ensure public/private members are nulled after processing. Separately, app/worker.php now logs previous-exception context (previous message when different, previous file, previous line) for both error logging and console warnings when a chained exception exists.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~30 minutes

  • Heterogeneous edits across two files: type/nullable changes, lifecycle cleanup and GC, expanded error logging formatting, new method and CSV export workflow, credential-check robustness, and enhanced exception-context logging.
  • Areas to inspect closely:
    • Call sites and assumptions about now-nullable properties (dbForProject, dbForPlatform, deviceForMigrations, deviceForFiles, project) and places that may dereference them without null checks.
    • Correctness and ordering of try/finally in action() and processMigration (ensure resources are cleaned only after all use and no post-finally access occurs).
    • Places invoking logError now that it can be null — verify safe guards or conditional calls.
    • Integration and side effects of handleCSVExportComplete(...) with mail, realtime, and storage flows.
    • Credential endpoint comparison changes (null-coalescing vs string) — ensure behavior matches intended fallback semantics.
    • Effects and appropriateness of calling gc_collect_cycles() in this context.
    • app/worker.php previous-exception logging — check for duplication, sensitive data disclosure, and consistent formatting with existing logs.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Description check ❓ Inconclusive The description is empty placeholder text from the contribution template with no actual content about the changes, making it completely uninformative about the PR's purpose. Provide a substantive description explaining the migration cleanup changes, their motivation, testing approach, and any related issues or PRs.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Migration cleanup' accurately reflects the main changes in the PR, which focus on cleanup and state management in the Migrations worker.
✨ 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 migration-cleanup

📜 Recent 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 b0b9c41 and c6214ef.

📒 Files selected for processing (1)
  • app/worker.php (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • app/worker.php
⏰ 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). (19)
  • GitHub Check: E2E Service Test (Messaging)
  • GitHub Check: E2E Service Test (Teams)
  • GitHub Check: E2E Service Test (VCS)
  • GitHub Check: E2E Service Test (Users)
  • GitHub Check: E2E Service Test (Sites)
  • GitHub Check: E2E Service Test (Projects)
  • GitHub Check: E2E Service Test (Proxy)
  • GitHub Check: E2E Service Test (Console)
  • GitHub Check: E2E Service Test (Functions)
  • GitHub Check: E2E Service Test (GraphQL)
  • GitHub Check: E2E Service Test (Account)
  • GitHub Check: E2E Service Test (Health)
  • GitHub Check: E2E Service Test (Databases/Legacy)
  • GitHub Check: E2E Service Test (Avatars)
  • GitHub Check: E2E Service Test (Site Screenshots)
  • GitHub Check: E2E Service Test (Dev Keys)
  • GitHub Check: E2E General Test
  • GitHub Check: Unit Test
  • GitHub Check: scan

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.

@github-actions
Copy link
Copy Markdown

github-actions bot commented Dec 14, 2025

Security Scan Results for PR

Docker Image Scan Results

Package Version Vulnerability Severity
libpng 1.6.51-r0 CVE-2025-66293 HIGH
libpng-dev 1.6.51-r0 CVE-2025-66293 HIGH

Source Code Scan Results

🎉 No vulnerabilities found!

@github-actions
Copy link
Copy Markdown

github-actions bot commented Dec 14, 2025

✨ Benchmark results

  • Requests per second: 1,163
  • Requests with 200 status code: 209,361
  • P99 latency: 0.165978646

⚡ Benchmark Comparison

Metric This PR Latest version
RPS 1,163 1,222
200 209,361 220,030
P99 0.165978646 0.168063602

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/Appwrite/Platform/Workers/Migrations.php (2)

382-382: Add null check before invoking nullable callable.

The logError property is now nullable (Line 60), but it's invoked without a null check. While the current flow sets logError in action() before calling processMigration(), defensive programming requires a null check.

Apply this diff to add null safety:

-                call_user_func($this->logError, $th, 'appwrite-worker', 'appwrite-queue-'.self::getName(), [
+                if ($this->logError !== null) {
+                    call_user_func($this->logError, $th, 'appwrite-worker', 'appwrite-queue-'.self::getName(), [
+                        'migrationId' => $migration->getId(),
+                        'source' => $migration->getAttribute('source') ?? '',
+                        'destination' => $migration->getAttribute('destination') ?? '',
+                    ]);
+                }
-                    'migrationId' => $migration->getId(),
-                    'source' => $migration->getAttribute('source') ?? '',
-                    'destination' => $migration->getAttribute('destination') ?? '',
-                ]);

408-408: Add null check before invoking nullable callable.

Same issue as Line 382: logError is nullable but invoked without a null check.

Apply this diff:

-                        ($this->logError)($error, 'appwrite-worker', 'appwrite-queue-' . self::getName(), [
+                        if ($this->logError !== null) {
+                            ($this->logError)($error, 'appwrite-worker', 'appwrite-queue-' . self::getName(), [
+                                'migrationId' => $migration->getId(),
+                                'source' => $migration->getAttribute('source') ?? '',
+                                'destination' => $migration->getAttribute('destination') ?? '',
+                                'resourceName' => $error->getResourceName(),
+                                'resourceGroup' => $error->getResourceGroup(),
+                            ]);
+                        }
-                            'migrationId' => $migration->getId(),
-                            'source' => $migration->getAttribute('source') ?? '',
-                            'destination' => $migration->getAttribute('destination') ?? '',
-                            'resourceName' => $error->getResourceName(),
-                            'resourceGroup' => $error->getResourceGroup(),
-                        ]);
🧹 Nitpick comments (2)
src/Appwrite/Platform/Workers/Migrations.php (2)

485-507: Clarify the try-finally structure for file size check.

The structure where file deletion is in try and error handling (email + exception) is in finally is unusual. The finally block always executes, which means even if deletion succeeds, the email is sent and exception is thrown. This appears intentional (to always notify and fail when size limit is exceeded), but the pattern is non-standard.

Consider restructuring for clarity:

 if ($sizeMB > $planFileSize) {
-    try {
-        $this->deviceForFiles->delete($path);
-    } finally {
-        $message = "Export file size {$sizeMB}MB exceeds your plan limit.";
+    $message = "Export file size {$sizeMB}MB exceeds your plan limit.";
+    
+    // Clean up the file
+    try {
+        $this->deviceForFiles->delete($path);
+    } catch (\Throwable $e) {
+        Console::error("Failed to delete oversized export file: " . $e->getMessage());
+    }

-        $this->dbForProject->updateDocument('migrations', $migration->getId(), $migration->setAttribute(
-            'errors',
-            json_encode(['code' => 0, 'message' => $message]),
-            Document::SET_TYPE_APPEND,
-        ));
+    // Update migration document with error
+    $this->dbForProject->updateDocument('migrations', $migration->getId(), $migration->setAttribute(
+        'errors',
+        json_encode(['code' => 0, 'message' => $message]),
+        Document::SET_TYPE_APPEND,
+    ));

-        $this->sendCSVEmail(
-            success: false,
-            project: $project,
-            user: $user,
-            options: $options,
-            queueForMails: $queueForMails,
-            sizeMB: $sizeMB
-        );
+    // Send failure notification
+    $this->sendCSVEmail(
+        success: false,
+        project: $project,
+        user: $user,
+        options: $options,
+        queueForMails: $queueForMails,
+        sizeMB: $sizeMB
+    );

-        throw new \Exception($message);
-    }
+    throw new \Exception($message);
 }

472-475: Consider adding defensive null checks for nullable Device properties.

While the normal flow ensures deviceForFiles is set before handleCSVExportComplete is called, the property is nullable (Line 47), suggesting defensive null checks would be prudent.

+if ($this->deviceForFiles === null) {
+    throw new \Exception('Device for files not initialized');
+}
+
 $path = $this->deviceForFiles->getPath($bucketId . '/' . $this->sanitizeFilename($filename) . '.csv');
 $size = $this->deviceForFiles->getFileSize($path);
📜 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 6aafe2d and 54ba59d.

📒 Files selected for processing (1)
  • src/Appwrite/Platform/Workers/Migrations.php (3 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
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.
📚 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/Migrations.php
⏰ 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). (20)
  • GitHub Check: E2E Service Test (Migrations)
  • GitHub Check: E2E Service Test (Webhooks)
  • GitHub Check: E2E Service Test (Proxy)
  • GitHub Check: E2E Service Test (Users)
  • GitHub Check: E2E Service Test (Messaging)
  • GitHub Check: E2E Service Test (Tokens)
  • GitHub Check: E2E Service Test (Sites)
  • GitHub Check: E2E Service Test (Avatars)
  • GitHub Check: E2E Service Test (Realtime)
  • GitHub Check: E2E Service Test (Health)
  • GitHub Check: E2E Service Test (Databases/Legacy)
  • GitHub Check: E2E Service Test (FunctionsSchedule)
  • GitHub Check: E2E Service Test (Functions)
  • GitHub Check: E2E Service Test (GraphQL)
  • GitHub Check: E2E Service Test (Databases/TablesDB)
  • GitHub Check: E2E Service Test (Account)
  • GitHub Check: E2E General Test
  • GitHub Check: E2E Service Test (Dev Keys)
  • GitHub Check: E2E Service Test (Site Screenshots)
  • GitHub Check: Benchmark
🔇 Additional comments (5)
src/Appwrite/Platform/Workers/Migrations.php (5)

44-60: LGTM: Nullable properties enable proper cleanup.

Making these properties nullable and initializing them appropriately supports the memory management strategy introduced in the finally blocks. This is beneficial for long-running worker processes.


128-142: LGTM: Proper resource cleanup for worker process.

The try-finally block ensures that injected dependencies are cleared after each migration job, which is essential for preventing memory leaks in long-running worker processes. The call to gc_collect_cycles() helps break circular references.


431-433: LGTM: Local variable cleanup aids memory management.

Nulling out these local variables in the finally block helps break references to potentially large objects (Transfer, Source, Destination), which aids garbage collection in long-running worker processes.


579-660: LGTM: Well-structured email notification method.

The method properly handles both success and failure cases with appropriate guard clauses, localization, and fallback values for plan properties. Template loading and email queuing follow established patterns.


668-675: LGTM: Robust filename sanitization.

The method properly sanitizes filenames by replacing problematic characters and provides a sensible fallback ('export') for edge cases where the entire filename consists of special characters.

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/Appwrite/Platform/Workers/Migrations.php (1)

488-509: Critical: Finally block unconditionally throws and will suppress exceptions.

The try-finally block has a serious issue: the finally block always executes and always throws an exception. This means:

  1. If delete() succeeds, the finally block throws as intended
  2. If delete() throws an exception, the finally block replaces that exception with its own, losing the original error information

This is incorrect usage of finally blocks, which should be for cleanup only, not for throwing exceptions.

Apply this diff to fix the control flow:

         if ($sizeMB > $planFileSize) {
-            try {
-                $this->deviceForFiles->delete($path);
-            } finally {
-                $message = "Export file size {$sizeMB}MB exceeds your plan limit.";
-
-                $this->dbForProject->updateDocument('migrations', $migration->getId(), $migration->setAttribute(
-                    'errors',
-                    json_encode(['code' => 0, 'message' => $message]),
-                    Document::SET_TYPE_APPEND,
-                ));
-
-                $this->sendCSVEmail(
-                    success: false,
-                    project: $project,
-                    user: $user,
-                    options: $options,
-                    queueForMails: $queueForMails,
-                    sizeMB: $sizeMB
-                );
-
-                throw new \Exception($message);
-            }
+            try {
+                $this->deviceForFiles->delete($path);
+            } catch (\Throwable $e) {
+                Console::warning("Failed to delete oversized export file: " . $e->getMessage());
+            }
+            
+            $message = "Export file size {$sizeMB}MB exceeds your plan limit.";
+
+            $this->dbForProject->updateDocument('migrations', $migration->getId(), $migration->setAttribute(
+                'errors',
+                json_encode(['code' => 0, 'message' => $message]),
+                Document::SET_TYPE_APPEND,
+            ));
+
+            $this->sendCSVEmail(
+                success: false,
+                project: $project,
+                user: $user,
+                options: $options,
+                queueForMails: $queueForMails,
+                sizeMB: $sizeMB
+            );
+
+            throw new \Exception($message);
         }
🧹 Nitpick comments (2)
src/Appwrite/Platform/Workers/Migrations.php (2)

44-60: Verify null-safety of property accesses throughout the class.

The properties dbForProject, dbForPlatform, deviceForMigrations, deviceForFiles, project, and logError are now nullable to support cleanup in the finally blocks. However, these properties are accessed throughout the class without null checks (e.g., lines 162, 220, 223, 258, 384, 410, etc.).

While the control flow ensures these properties are non-null during processMigration execution, the type system cannot guarantee this. Consider either:

  1. Adding assertions at the start of methods that depend on these properties
  2. Using a non-nullable pattern with explicit cleanup mechanisms
  3. Adding null-coalescing operators or null checks where appropriate

Run the following script to identify all property accesses that may need null checks:

#!/bin/bash
# Description: Find all accesses to nullable properties that may need null-safety checks

echo "=== Accesses to \$this->dbForProject ==="
rg -n '\$this->dbForProject' --type php -C2

echo -e "\n=== Accesses to \$this->dbForPlatform ==="
rg -n '\$this->dbForPlatform' --type php -C2

echo -e "\n=== Accesses to \$this->project ==="
rg -n '\$this->project' --type php -C2

echo -e "\n=== Accesses to \$this->logError ==="
rg -n '\$this->logError' --type php -C2

echo -e "\n=== Accesses to \$this->deviceForMigrations ==="
rg -n '\$this->deviceForMigrations' --type php -C2

echo -e "\n=== Accesses to \$this->deviceForFiles ==="
rg -n '\$this->deviceForFiles' --type php -C2

433-435: Optional: Nulling local variables is redundant.

The local variables $transfer, $source, and $destination are explicitly nulled in the finally block. Since they go out of scope when the function returns, this is technically redundant. However, it's harmless and may serve as defensive programming to ensure immediate resource cleanup, especially in exception scenarios.

📜 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 54ba59d and 91a3ee0.

📒 Files selected for processing (1)
  • src/Appwrite/Platform/Workers/Migrations.php (4 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
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.
📚 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/Migrations.php
⏰ 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). (1)
  • GitHub Check: scan
🔇 Additional comments (4)
src/Appwrite/Platform/Workers/Migrations.php (4)

128-142: LGTM! Explicit cleanup appropriate for worker processes.

The try-finally block ensures proper resource cleanup after each migration job, which is essential for long-running worker processes. Nulling dependencies and calling gc_collect_cycles() helps prevent memory leaks across multiple job executions.


375-377: LGTM! Enhanced error context.

The additional file and line number logging improves debugging information for migration failures.


568-662: LGTM! Well-structured email notification.

The email notification logic properly handles both success and failure cases with appropriate localization and templating. The early returns for edge cases (notify flag and missing user) are appropriate.


664-677: LGTM! Adequate filename sanitization.

The sanitization logic appropriately removes filesystem-unsafe characters and provides a reasonable fallback.

…ration-cleanup

# Conflicts:
#	src/Appwrite/Platform/Workers/Migrations.php
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

🧹 Nitpick comments (1)
src/Appwrite/Platform/Workers/Migrations.php (1)

493-496: Consider using null coalescing instead of empty() for file size check.

The empty() function treats 0 as empty, so if $this->plan['fileSize'] is explicitly set to 0, it will default to PHP_INT_MAX (no limit). This might be incorrect if 0 should mean "no files allowed."

Consider this change to only use the default when the key doesn't exist:

-$planFileSize = empty($this->plan['fileSize'])
-    ? PHP_INT_MAX
-    : $this->plan['fileSize'];
+$planFileSize = $this->plan['fileSize'] ?? PHP_INT_MAX;

This distinguishes between "not set" (defaults to no limit) and "set to 0" (enforces limit).

📜 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 6fbacb4 and 1c165b8.

📒 Files selected for processing (1)
  • src/Appwrite/Platform/Workers/Migrations.php (5 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
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.
📚 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/Migrations.php
🧬 Code graph analysis (1)
src/Appwrite/Platform/Workers/Migrations.php (2)
src/Appwrite/Utopia/Response/Model/Document.php (1)
  • Document (8-115)
src/Appwrite/Event/Messaging.php (1)
  • getMessage (90-93)
⏰ 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). (20)
  • GitHub Check: E2E Service Test (Console)
  • GitHub Check: E2E Service Test (Teams)
  • GitHub Check: E2E Service Test (Storage)
  • GitHub Check: E2E Service Test (Health)
  • GitHub Check: E2E Service Test (VCS)
  • GitHub Check: E2E Service Test (Avatars)
  • GitHub Check: E2E Service Test (Messaging)
  • GitHub Check: E2E Service Test (Tokens)
  • GitHub Check: E2E Service Test (GraphQL)
  • GitHub Check: E2E Service Test (Projects)
  • GitHub Check: E2E Service Test (Functions)
  • GitHub Check: E2E Service Test (Databases/TablesDB)
  • GitHub Check: E2E Service Test (Proxy)
  • GitHub Check: E2E Service Test (Databases/Legacy)
  • GitHub Check: Unit Test
  • GitHub Check: E2E Service Test (Site Screenshots)
  • GitHub Check: E2E General Test
  • GitHub Check: E2E Service Test (Dev Keys)
  • GitHub Check: Setup & Build Appwrite Image
  • GitHub Check: scan
🔇 Additional comments (9)
src/Appwrite/Platform/Workers/Migrations.php (9)

44-59: LGTM: Explicit nullability supports robust cleanup.

Making these properties nullable and initializing plan and logError with defaults is good practice. This enables the explicit cleanup pattern in the action() finally block to prevent memory leaks in long-running workers.


126-139: LGTM: Comprehensive cleanup pattern for worker lifecycle.

The try/finally pattern ensures all references are cleared and state is reset after each migration. Calling gc_collect_cycles() is appropriate for long-running workers to proactively free memory from circular references, especially after processing large migrations.


156-156: LGTM: Defensive null-coalescing prevents array key errors.

Using the null coalescing operator prevents errors when the endpoint key is missing from credentials.


385-388: LGTM: Enhanced error diagnostics.

Breaking out the error message, file, and line into separate console logs improves debugging visibility compared to relying solely on the stack trace.


443-445: LGTM: Explicit nulling aids garbage collection.

Nulling these transfer-related locals in the finally block helps PHP's garbage collector handle any circular references within the Transfer, Source, or Destination objects. This is good practice for long-running workers.


468-468: Verify hardcoded 'default' bucket is correct for all CSV exports.

The bucket ID is hardcoded to 'default'. Please confirm that all CSV export files should always use the platform default bucket and that this won't cause issues with custom bucket configurations.


461-576: LGTM: Comprehensive CSV export completion flow.

The method properly handles:

  • User and bucket validation
  • File document creation with appropriate permissions
  • JWT generation for secure downloads (1-hour expiry)
  • Download URL construction with authentication
  • Success/failure email notifications

The implementation is thorough and includes proper error handling for plan limit violations.


591-672: LGTM: Well-structured notification with i18n support.

The email method properly:

  • Respects user notification preferences
  • Uses locale for internationalization
  • Differentiates success/failure templates
  • Provides sensible fallbacks for branding variables

680-687: LGTM: Robust filename sanitization.

The method properly sanitizes filenames by:

  • Replacing filesystem-unsafe characters with underscores
  • Removing non-printable characters
  • Providing a safe fallback name

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: 1

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

442-447: LGTM! Enhanced error visibility for chained exceptions.

The console output for previous exceptions improves debugging by surfacing the full error chain.

Optional refactor to reduce duplication:

The logic for extracting and formatting previous exception details is duplicated between the persistent log path (lines 414-420) and console output path (lines 442-447). Consider using strict comparison (!==) on line 443, consistent with the suggestion for line 415.

📜 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 1c165b8 and b0b9c41.

📒 Files selected for processing (1)
  • app/worker.php (2 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
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.
⏰ 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). (20)
  • GitHub Check: E2E Service Test (Webhooks)
  • GitHub Check: E2E Service Test (Tokens)
  • GitHub Check: E2E Service Test (Messaging)
  • GitHub Check: E2E Service Test (Users)
  • GitHub Check: E2E Service Test (Sites)
  • GitHub Check: E2E Service Test (Migrations)
  • GitHub Check: E2E Service Test (Health)
  • GitHub Check: E2E Service Test (Realtime)
  • GitHub Check: E2E Service Test (VCS)
  • GitHub Check: E2E Service Test (Projects)
  • GitHub Check: E2E Service Test (Locale)
  • GitHub Check: E2E Service Test (Databases/Legacy)
  • GitHub Check: E2E Service Test (Storage)
  • GitHub Check: E2E Service Test (FunctionsSchedule)
  • GitHub Check: E2E Service Test (Databases/TablesDB)
  • GitHub Check: E2E Service Test (Site Screenshots)
  • GitHub Check: E2E General Test
  • GitHub Check: Unit Test
  • GitHub Check: E2E Service Test (Dev Keys)
  • GitHub Check: scan

@abnegate abnegate merged commit 9b62d34 into 1.8.x Dec 16, 2025
41 checks passed
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