Skip to content
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

feat: wasm worker manager #966

Merged
merged 36 commits into from
Jan 29, 2025
Merged

feat: wasm worker manager #966

merged 36 commits into from
Jan 29, 2025

Conversation

luckasRanarison
Copy link
Contributor

@luckasRanarison luckasRanarison commented Jan 22, 2025

Migration notes


  • The change comes with new or modified tests
  • Hard-to-understand functions have explanatory comments
  • End-user documentation is updated to reflect the change

Summary by CodeRabbit

Release Notes

  • New Features

    • Added WebAssembly (WASM) worker management capabilities.
    • Introduced new type definitions for WASM runtime interactions.
    • Enhanced worker pool and worker manager functionality.
    • Introduced a new WasmWorker class for managing WebAssembly workers.
  • Configuration Changes

    • Updated global configuration to include WASM worker-related settings.
    • Replaced substantial_worker_wait_timeout_ms with more granular worker configuration options.
    • Added new environment variables for WASM worker management: MIN_WASM_WORKERS and MAX_WASM_WORKERS.
  • Runtime Improvements

    • Refactored runtime initialization processes.
    • Improved worker lifecycle management.
    • Enhanced error handling and logging for various runtime environments.
    • Removed explicit destroy operations in some runtime components.
  • Dependency Updates

    • Updated Metatype version to 0.5.1-rc.0.
  • Performance Optimizations

    • Added pre-warming steps in performance tests.
    • Streamlined worker initialization and management.
  • Code Quality

    • Improved code formatting and readability.
    • Simplified runtime and worker management interfaces.

Copy link

linear bot commented Jan 22, 2025

Copy link
Contributor

coderabbitai bot commented Jan 22, 2025

📝 Walkthrough

Walkthrough

This pull request introduces significant architectural changes to the TypeGate runtime system, focusing on enhancing worker management, WebAssembly (Wasm) runtime interactions, and refactoring various runtime components. The changes primarily involve decoupling the existing WitWire messaging system, introducing a new worker management approach, and restructuring how different runtime environments handle operations and worker lifecycles. Key modifications include removing the destroy operation from the wit_wire object, adding WebAssembly worker support, updating configuration schemas, and simplifying resource management across different runtime implementations.

Changes

File Change Summary
src/typegate/engine/00_runtime.js Removed destroy operation from wit_wire object
src/typegate/engine/runtime.d.ts Removed destroy method from WitWire namespace
src/typegate/engine/src/ext.rs Removed wit_wire::op_wit_wire_destroy operation registration
src/typegate/engine/src/runtimes/wit_wire.rs Added id field to Instance struct, implemented Drop trait for automatic cleanup
src/typegate/src/config/types.ts Updated global configuration schema with Wasm worker-related properties
src/typegate/src/runtimes/wasm/types.ts Added new type definitions for Wasm messaging and task specifications
src/typegate/src/runtimes/wasm/worker_manager.ts Introduced new WorkerManager for Wasm workers
src/typegate/src/types.ts Added WitOpArgs interface and WitWireMatInfo import
Multiple runtime files Updated runtime initialization and worker management approaches

Suggested reviewers

  • Natoandro
  • michael-0acf4
  • Yohe-Am
  • zifeo

Possibly related PRs


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2bc7721 and af729a7.

📒 Files selected for processing (1)
  • src/typegate/src/runtimes/patterns/worker_manager/pooling.ts (5 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/typegate/src/runtimes/patterns/worker_manager/pooling.ts
⏰ Context from checks skipped due to timeout of 90000ms (5)
  • GitHub Check: lint-compat (macos-14, aarch64-apple-darwin, false)
  • GitHub Check: test-full
  • GitHub Check: bulid-docker (linux/amd64, custom-ubuntu-large)
  • GitHub Check: lint-compat (macos-13, x86_64-apple-darwin, false)
  • GitHub Check: pre-commit

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@luckasRanarison luckasRanarison changed the base branch from main to met-806-worker-pooling January 24, 2025 06:38
Copy link
Contributor

@Natoandro Natoandro left a comment

Choose a reason for hiding this comment

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

😵‍💫😵‍💫

Base automatically changed from met-806-worker-pooling to main January 27, 2025 19:20
@luckasRanarison luckasRanarison marked this pull request as ready for review January 28, 2025 09:13
@luckasRanarison luckasRanarison requested a review from a team January 28, 2025 09:15
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: 4

🧹 Nitpick comments (9)
src/typegate/src/runtimes/wasm/worker_manager.ts (1)

86-88: Structured, consistent logging.

Using logger.info for normal flow and logger.debug for more detailed insights is a good practice. Consider adding an optional context string or request ID to logs for better traceability across multiple tasks.

src/typegate/src/runtimes/wasm_wire.ts (1)

140-150: Asynchronous call to the worker.

  1. You log the operation, call workerManager.callWitOp, and return the result once available.
  2. The additional logging for both success and debug details helps users pinpoint potential failures or track performance.

Ensure that large responses don’t congest logs; consider a truncation or separate debug-level logs for very large payloads.

src/typegate/src/runtimes/wit_wire/mod.ts (2)

14-33: Consider retaining the hostcall function reference in the class.
The hostcall function is passed into init() but isn't stored in the constructed instance. If future usage demands calling hostcall on the instance, consider storing it. Otherwise, clarifying why it's not stored may prevent confusion.


Line range hint 133-159: Throwing objects instead of native Error may impact debugging.
Here, we throw a plain object containing code, message, and optional cause. Throwing a native Error preserves the stack trace and aligns with typical error-handling patterns. Consider adopting Error builds for consistency.

src/typegate/src/runtimes/wasm/types.ts (1)

18-22: Consider normalizing error reporting in WasmEvent.
Storing a raw Error object might be tricky when crossing worker boundaries. You may want to serialize relevant error fields or create a standardized error response shape for reliability.

src/typegate/src/runtimes/wasm/worker.ts (1)

24-58: Enhance error handling and add resource cleanup.

The message handler could benefit from more robust error handling and resource management.

Consider these improvements:

 self.onmessage = async function (event: MessageEvent<WasmMessage>) {
   const { type } = event.data;
 
   switch (type) {
     case "CALL": {
-      const { id } = event.data;
+      const { id, operation } = event.data;
+      console.debug(`Processing ${operation} for instance ${id}`);
 
       if (!witWireInstances.has(id)) {
         const handle = await WitWireHandle.init({
           ...event.data,
           hostcall,
         });
         witWireInstances.set(id, handle);
+        console.debug(`Created new WitWireHandle instance ${id}`);
       }
 
       try {
         self.postMessage({
           type: "SUCCESS",
           result: await handleWitOp(event.data),
         });
       } catch (error) {
+        const errorMessage = error instanceof Error ? error.message : String(error);
+        console.error(`Operation failed for instance ${id}: ${errorMessage}`);
         self.postMessage({
           type: "FAILURE",
-          error: errorToString(error),
+          error: errorMessage,
           exception: error,
         });
+      } finally {
+        // Clean up terminated instances
+        if (event.data.operation === "terminate") {
+          witWireInstances.delete(id);
+          console.debug(`Cleaned up instance ${id}`);
+        }
       }
 
       break;
     }
 
     default:
-      throw new Error(`Unknown message type: ${type}`);
+      const error = `Unknown message type: ${type}`;
+      console.error(error);
+      self.postMessage({
+        type: "FAILURE",
+        error,
+      });
   }
 };
src/typegate/src/runtimes/patterns/worker_manager/pooling.ts (2)

24-24: Add JSDoc comment for the clear method.

Consider adding documentation to explain the purpose and behavior of the clear method.

+  /** Clears any pending tasks in the queue and releases associated resources. */
   clear: () => void;

81-89: Enhance clear method implementation.

The clear method should also handle pending queue items.

   clear() {
     if (this.#timerId != null) {
       clearTimeout(this.#timerId);
+      this.#timerId = null;
     }
+    // Cancel all pending items in the queue
+    while (this.#queue.length > 0) {
+      this.#cancelNextEntry();
+    }
   }

   [Symbol.dispose]() {
     this.clear();
   }
src/typegate/src/types.ts (1)

53-59: Add JSDoc documentation for the WitOpArgs interface.

The interface structure looks good and aligns well with WebAssembly worker management needs. However, it would benefit from JSDoc documentation explaining the purpose and usage of each property.

Consider adding documentation like this:

+/**
+ * Interface for WebAssembly operation arguments used in worker management.
+ */
 export interface WitOpArgs {
+  /** Name of the WebAssembly operation to execute */
   opName: string;
+  /** Resolver arguments containing parent, variables, context, and other metadata */
   args: ResolverArgs;
+  /** Unique identifier for the operation */
   id: string;
+  /** Path to the WebAssembly component */
   componentPath: string;
+  /** Array of WitWire materialization information for the operations */
   ops: WitWireMatInfo[];
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1c5420a and 4b8e000.

⛔ Files ignored due to path filters (1)
  • deno.lock is excluded by !**/*.lock
📒 Files selected for processing (22)
  • src/typegate/engine/00_runtime.js (0 hunks)
  • src/typegate/engine/runtime.d.ts (0 hunks)
  • src/typegate/engine/src/ext.rs (0 hunks)
  • src/typegate/engine/src/runtimes/wit_wire.rs (2 hunks)
  • src/typegate/src/config/types.ts (2 hunks)
  • src/typegate/src/runtimes/deno/deno.ts (6 hunks)
  • src/typegate/src/runtimes/patterns/worker_manager/deno.ts (2 hunks)
  • src/typegate/src/runtimes/patterns/worker_manager/mod.ts (3 hunks)
  • src/typegate/src/runtimes/patterns/worker_manager/pooling.ts (4 hunks)
  • src/typegate/src/runtimes/patterns/worker_manager/wasm.ts (1 hunks)
  • src/typegate/src/runtimes/python.ts (4 hunks)
  • src/typegate/src/runtimes/substantial.ts (4 hunks)
  • src/typegate/src/runtimes/substantial/agent.ts (9 hunks)
  • src/typegate/src/runtimes/wasm/types.ts (1 hunks)
  • src/typegate/src/runtimes/wasm/worker.ts (1 hunks)
  • src/typegate/src/runtimes/wasm/worker_manager.ts (1 hunks)
  • src/typegate/src/runtimes/wasm_wire.ts (4 hunks)
  • src/typegate/src/runtimes/wit_wire/mod.ts (4 hunks)
  • src/typegate/src/types.ts (2 hunks)
  • tests/runtimes/python/python_sync_test.ts (4 hunks)
  • tests/runtimes/python/python_test.ts (10 hunks)
  • tests/runtimes/wasm_wire/rust/fdk.rs (1 hunks)
💤 Files with no reviewable changes (3)
  • src/typegate/engine/runtime.d.ts
  • src/typegate/engine/src/ext.rs
  • src/typegate/engine/00_runtime.js
✅ Files skipped from review due to trivial changes (4)
  • tests/runtimes/wasm_wire/rust/fdk.rs
  • tests/runtimes/python/python_test.ts
  • src/typegate/src/runtimes/patterns/worker_manager/mod.ts
  • src/typegate/src/runtimes/patterns/worker_manager/deno.ts
⏰ Context from checks skipped due to timeout of 90000ms (6)
  • GitHub Check: bulid-docker (linux/arm64, custom-arm)
  • GitHub Check: lint-compat (macos-14, aarch64-apple-darwin, false)
  • GitHub Check: lint-compat (macos-13, x86_64-apple-darwin, false)
  • GitHub Check: bulid-docker (linux/amd64, custom-ubuntu-large)
  • GitHub Check: test-full
  • GitHub Check: pre-commit
🔇 Additional comments (39)
src/typegate/src/runtimes/patterns/worker_manager/wasm.ts (6)

10-12: Good use of private fields for worker encapsulation.

Declaring #worker and #workerId ensures these properties remain private and inaccessible outside the WasmWorker class. This helps maintain a clear separation of concerns and avoids accidental external mutations.


13-14: Constructor clarity.

The constructor properly captures and stores the workerId, which is essential for identifying this worker instance. Good job also calling super() to ensure the base class is properly initialized.


46-48: Message posting is straightforward.

The send method correctly posts messages to the worker’s queue. This is a standard approach to decouple message preparation from the core worker logic.


50-52: Graceful termination.

Terminating the worker prevents resource leaks. Ensure that you consistently call destroy() in higher-level code when the worker is no longer needed.


54-56: Convenient accessor for worker ID.

The id getter is a simple, handy way to retrieve the worker’s identifier. This is especially useful for logging or debugging purposes.


15-31: Evaluate permissions for security and functionality.

A “FIXME” note suggests uncertainty about the correct permissions. Currently, most permissions are disabled, except for network communication (“net”), read inheritance, system calls, and environment variables shared with workers. Ensure these minimal permission settings still allow all necessary operations without opening unnecessary attack vectors.

You can run a safety check or dynamic tests that validate the worker's behavior under these restrictive permissions:

✅ Verification successful

Current permission settings are secure and appropriate

The permission configuration follows the principle of least privilege:

  • Enabled permissions (net, read, sys, env) are necessary for worker functionality
  • High-risk permissions (run, write, ffi) are correctly disabled to prevent security vulnerabilities
  • Environment variables are selectively shared through envSharedWithWorkers
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Attempt to run the new WasmWorker with typical tasks and detect any permission issues
# This script checks for potential runtime errors or permission denials.
rg "new WasmWorker" -A 10

Length of output: 830


Script:

#!/bin/bash
# Find worker implementation and permission-related content
echo "=== Worker Implementation ==="
rg -t typescript "class WasmWorker" -A 20

echo -e "\n=== Permission Related Errors/Issues ==="
rg -i "permission|denied" --type typescript

echo -e "\n=== Security Documentation ==="
fd "README|SECURITY" --extension md --exec cat {}

Length of output: 6896


Script:

#!/bin/bash
# Find and analyze worker implementation with correct file extensions
echo "=== TypeScript Files ==="
fd -e ts -e tsx . src/typegate/src/runtimes/

echo -e "\n=== Worker Implementation ==="
fd -e ts -e tsx . src/typegate/src/runtimes/ --exec cat {}

echo -e "\n=== Permission Usage Patterns ==="
rg -l "permissions.*\{" --type-add 'typescript:*.{ts,tsx}' -t typescript

Length of output: 68267

src/typegate/src/runtimes/wasm/worker_manager.ts (4)

19-23: Class structure is logically consistent.

WorkerManager inherits from BaseWorkerManager and follows a cohesive pattern for managing tasks, messages, and events. The generics (TaskSpec, WasmMessage, WasmEvent) ensure type safety.


24-38: Evaluate the lazy initialization of the pool.

#getPool() stores the pool in a static variable to avoid multiple instantiations. Make sure to handle cleanup scenarios. For instance, if the server restarts or if workers need to be forcibly reinitialized, consider whether a re-init or a pool reset is required.


40-42: Injecting host call context is well-designed.

Passing hostcallCtx to the constructor allows the manager to handle environment-specific logic. This ensures a single source of truth for host call data.


44-84: Robust asynchronous workflow with event-driven messaging.

  1. callWitOp manages the entire lifecycle of a task.
  2. It delegates, sends a “CALL” message, and returns a promise that resolves or rejects based on the worker’s response.
  3. The handler function accommodates special “HOSTCALL” messages, bridging the worker environment with hostcall.

Overall, this design is clear and maintainable.

src/typegate/src/runtimes/wasm_wire.ts (6)

13-13: Decouple internal vs. external import.

Importing WitWireMatInfo from a .js file might lead to confusion if other types are TS-based. Confirm that this .js module is intended, or consider unifying the import style to .ts for consistency.


25-28: Constructor argument structure is coherent.

The addition of componentPath, wireMat, and workerManager clarifies the runtime’s dependencies. This fosters better management of WASM runtime resources and worker interactions.


57-67: Local artifact path retrieval.

componentPath is derived from the artifact store, and wireMat is mapped from the provided materializers. This approach ensures the runtime is fully aware of all relevant metadata for the WASM artifact.


68-75: Host call context set up.

You maintain the auth token and references to the typegate, as well as the typegraphUrl. This is critical for bridging function calls back to the host.


76-82: WorkerManager instantiation.

Instantiating WorkerManager with the newly created hostcallCtx is straightforward. This keeps the worker environment self-contained, with minimal knowledge of the outside world.


86-87: Methodical teardown process.

deinit() calls workerManager.deinit() to properly shut down the manager. This helps prevent resource leaks or orphaned workers.

src/typegate/src/runtimes/wit_wire/mod.ts (3)

6-6: All good on the import statement.
No issues spotted with the import of ResolverArgs and WitOpArgs.


52-53: Constructor usage looks fine.
No issues with the constructor arguments or assignments.


55-123: Handle JSON parse failures gracefully.
When parsing res.Ok, a malformed JSON string would trigger a runtime error. If the expected data source is under your control, this may not be an issue. Otherwise, consider a try/catch around JSON.parse to provide a clearer error.

src/typegate/src/runtimes/python.ts (5)

15-15: Import statement verified.
Import of WorkerManager is consistent with the newly introduced architecture.


24-26: Constructor signature changes look coherent.
Adding wireMat and workerManager clarifies responsibilities for Python-based operations.


126-134: Ensure authorized usage of the hostcall context.
Creating hostcallCtx with an internal token is a good approach for internal requests. Verify that the token usage matches your security guidelines and is invalidated where necessary.


144-148: Properly de-initializing worker resources.
Explicitly calling this.workerManager.deinit() ensures WASM workers are shut down. Good resource hygiene.


203-217: Delegate method logic appears consistent.
Renaming opName and routing calls through this.workerManager is aligned with the new design. The logging statements are helpful for debugging.

src/typegate/src/runtimes/wasm/types.ts (3)

6-9: TaskSpec definition is clear.
No issues spotted; it effectively documents the required shape of the task.


11-11: WasmCallMessage typed well.
Merging the WitOpArgs with a { type: "CALL" } discriminates call messages nicely.


13-16: Union type for WasmMessage is concise.
This union covers calls, hostcall results, and shutdown messages well.

src/typegate/src/runtimes/wasm/worker.ts (1)

1-8: LGTM!

The imports and Map initialization are well-structured and properly organized.

src/typegate/src/config/types.ts (1)

95-95: LGTM!

The error message formatting change improves readability while maintaining the same information.

src/typegate/src/runtimes/deno/deno.ts (2)

37-40: LGTM!

The function formatting changes improve code readability while maintaining the same functionality.

Also applies to: 46-51, 73-73


191-191: Properly await async cleanup.

The addition of await is crucial for proper resource cleanup.

Let's verify that all deinit calls are properly awaited:

✅ Verification successful

Async cleanup properly handled across the codebase

The addition of await for workerManager.deinit() is correct. All async cleanup operations in the codebase are properly awaited, and synchronous operations (like redis.close() and client.close()) are correctly handled without await as indicated by the deno-lint-ignore require-await directives.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for async deinit methods that might be called without await
rg -g '*.ts' 'async\s+deinit.*\{' -A 5

Length of output: 5733


Script:

#!/bin/bash
# Check if redis.close() and client.close() are async
rg -g '*.ts' '(redis|client)\.close\(' -B 5

Length of output: 1402

tests/runtimes/python/python_sync_test.ts (2)

192-193: Great addition of pre-warming step!

The pre-warming step helps eliminate cold-start bias from the performance measurements by executing the first 10 test cases before starting the timer.


310-310: LGTM: Improved test names readability.

The test names are now more consistent and readable.

Also applies to: 388-388, 422-422

src/typegate/src/runtimes/substantial/agent.ts (1)

115-116: Important: Method is now async to properly await worker cleanup.

The stop method has been correctly updated to be async, ensuring proper cleanup by awaiting the worker manager's deinitialization.

src/typegate/src/runtimes/substantial.ts (1)

151-153: Good: Method is now async to properly await agent cleanup.

The deinit method has been correctly updated to be async, ensuring proper cleanup by awaiting the agent's stop operation. This change aligns with the async changes in agent.ts.

src/typegate/engine/src/runtimes/wit_wire.rs (3)

99-99: Good: Added automatic cleanup with Drop implementation.

The Instance struct now includes an id field and implements Drop trait for automatic cleanup, which is a better approach than manual cleanup. The Drop implementation ensures that preopened directories are properly cleaned up when instances are dropped.

Also applies to: 105-129


411-413: LGTM: Instance creation now properly stores the id.

The instance creation has been updated to store the instance id, which is necessary for the new cleanup mechanism.


112-112: Consider reviewing the async cleanup necessity.

The FIXME comment questions whether the cleanup really needs to be async. This is a valid concern as file system operations could potentially be done synchronously during cleanup.

Run this script to analyze the impact of directory removal operations:

✅ Verification successful

The async cleanup is appropriate and should be retained

The async implementation is the correct approach here as this is a cleanup operation in a Drop implementation. Using synchronous file system operations would block the destructor, while the current fire-and-forget async approach allows the cleanup to proceed in the background without impacting performance. The FIXME comment can be safely removed.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for similar cleanup patterns in the codebase
rg -A 5 "remove_dir_all" 

Length of output: 2647


Script:

#!/bin/bash
# Get broader context around the cleanup operation
rg -B 10 -A 10 "FIXME: Does it really have to be async" src/typegate/engine/src/runtimes/wit_wire.rs

Length of output: 826

src/typegate/src/types.ts (1)

17-17: Verify the import path and type existence.

Let's ensure the imported type exists and the path is correct.

✅ Verification successful

Import statement is correct and properly used

The WitWireMatInfo type is correctly defined in the target file and is consistently used across the codebase for WebAssembly runtime interactions.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the import path and WitWireMatInfo type existence

# Check if the file exists
fd -e ts -e d.ts "runtime.d.ts" src/

# Check for WitWireMatInfo type definition
rg -t typescript "export.*WitWireMatInfo" src/

Length of output: 153


Script:

#!/bin/bash
# Check for WitWireMatInfo type definition without file type restriction
rg "export.*WitWireMatInfo" src/typegate/engine/runtime.d.ts

# Also check for any usage of WitWireMatInfo to understand the context
rg "WitWireMatInfo" src/

Length of output: 1628

src/typegate/src/runtimes/patterns/worker_manager/wasm.ts Outdated Show resolved Hide resolved
src/typegate/src/runtimes/wasm/worker.ts Show resolved Hide resolved
src/typegate/src/config/types.ts Show resolved Hide resolved
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: 2

♻️ Duplicate comments (1)
src/typegate/src/runtimes/patterns/worker_manager/wasm.ts (1)

41-43: 🛠️ Refactor suggestion

Enhance error handling with logging and recovery strategy.

The current error handling simply throws the error, which could lead to unhandled worker failures. Consider adding logging and implementing a recovery strategy.

-    this.#worker.onerror = (event) => {
-      throw event.error;
-    };
+    this.#worker.onerror = (event) => {
+      console.error(`[WasmWorker ${this.#workerId}] Worker error:`, event.error);
+      // Consider implementing a recovery strategy:
+      // - Attempt to restart the worker
+      // - Notify the worker manager
+      // - Clean up resources
+      throw event.error;
+    };
🧹 Nitpick comments (4)
docs/metatype.dev/docs/reference/typegate/index.mdx (1)

90-91: Consider adding WASM_WORKER_WAIT_TIMEOUT_MS configuration.

For consistency with other worker configurations (e.g., DENO_WORKER_WAIT_TIMEOUT_MS), consider adding documentation for the WASM worker timeout configuration.

Add the following entry to the table:

 | MAX_WASM_WORKERS                   | Maximal number of available wasm workers                                                                 | 8                        | 16                                                                                       |
+| WASM_WORKER_WAIT_TIMEOUT_MS        | Timeout for waiting for a free wasm worker                                                              | 5000                     | 2000                                                                                     |
 | SUBSTANTIAL_WORKER_WAIT_TIMEOUT_MS | Timeout for waiting for a free substantial worker                                                        | 15000                    | 2000                                                                                     |
src/typegate/src/runtimes/patterns/worker_manager/wasm.ts (3)

5-6: Consider combining imports from the same module.

The imports from ../../wasm/types.ts can be combined into a single import statement for better maintainability.

-import { WasmEvent } from "../../wasm/types.ts";
-import { WasmMessage } from "../../wasm/types.ts";
+import { WasmEvent, WasmMessage } from "../../wasm/types.ts";

50-52: Enhance worker cleanup in destroy method.

The destroy method terminates the worker but doesn't ensure proper cleanup of resources or handle pending operations.

   destroy() {
+    // Clean up any pending operations
+    try {
       this.#worker.terminate();
+    } catch (error) {
+      console.error(`[WasmWorker ${this.#workerId}] Error during termination:`, error);
+    }
+    // Reset internal state
+    this.#worker = null!;
   }

46-48: Add error handling to send method.

The send method should handle potential errors that could occur during postMessage, especially for large messages or if the worker is terminated.

   send(msg: WasmMessage) {
-    this.#worker.postMessage(msg);
+    try {
+      this.#worker.postMessage(msg);
+    } catch (error) {
+      console.error(`[WasmWorker ${this.#workerId}] Error sending message:`, error);
+      throw error;
+    }
   }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3498852 and 6a61cce.

📒 Files selected for processing (4)
  • docs/metatype.dev/docs/reference/typegate/index.mdx (1 hunks)
  • src/typegate/engine/src/runtimes/wit_wire.rs (2 hunks)
  • src/typegate/src/runtimes/patterns/worker_manager/pooling.ts (2 hunks)
  • src/typegate/src/runtimes/patterns/worker_manager/wasm.ts (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (6)
  • GitHub Check: lint-compat (macos-14, aarch64-apple-darwin, false)
  • GitHub Check: bulid-docker (linux/arm64, custom-arm)
  • GitHub Check: lint-compat (macos-13, x86_64-apple-darwin, false)
  • GitHub Check: bulid-docker (linux/amd64, custom-ubuntu-large)
  • GitHub Check: test-full
  • GitHub Check: pre-commit
🔇 Additional comments (7)
docs/metatype.dev/docs/reference/typegate/index.mdx (1)

90-91: LGTM! Documentation is clear and consistent.

The new WASM worker configuration variables are well-documented and follow the same pattern as other worker configurations in the system.

src/typegate/engine/src/runtimes/wit_wire.rs (2)

99-99: LGTM! Good addition of instance identifier.

The addition of the id field to the Instance struct enhances worker management by enabling proper tracking and cleanup of instances.


Line range hint 413-419: LGTM! Proper instance initialization with ID.

The instance initialization correctly clones and stores the instance ID, which is necessary for both the map key and Instance struct.

src/typegate/src/runtimes/patterns/worker_manager/pooling.ts (3)

92-93: LGTM!

The timeout calculation reformatting improves readability while maintaining the same logic.


Line range hint 1-224: Consider WASM-specific worker lifecycle management.

Given that this PR focuses on WASM worker management, consider if WASM workers require special handling in the worker pool, such as:

  • Initialization time for WASM module loading
  • Memory management considerations
  • Specific cleanup requirements

Let's check for WASM-specific worker implementations:


217-221: Handle potential race condition in worker destruction.

The current implementation might clear the workers array before all workers are fully destroyed if worker.destroy() is asynchronous.

Let's verify if worker.destroy() is asynchronous:

If destroy() is asynchronous, consider this enhancement:

  clear() {
    logger.warn(
      `destroying idle workers: ${this.#idleWorkers
        .map((w) => `"${w.id}"`)
        .join(", ")}`,
    );
-   this.#idleWorkers.forEach((worker) => worker.destroy());
-   this.#idleWorkers = [];
+   const workers = this.#idleWorkers;
+   this.#idleWorkers = [];
+   return Promise.all(workers.map((worker) => worker.destroy()));
  }
src/typegate/src/runtimes/patterns/worker_manager/wasm.ts (1)

19-30: Verify worker permissions configuration.

The FIXME comment suggests uncertainty about the correct permissions. Let's verify:

  • Network access is enabled (net: true)
  • File read and system permissions are inherited
  • Security-critical permissions (run, write, ffi) are correctly disabled
  • Environment variables are restricted to a shared subset

Let's analyze the permission configuration:

✅ Verification successful

Remove FIXME comment - permissions are correctly configured

The current permission configuration is secure and consistent across worker implementations. It properly implements the principle of least privilege by:

  • Enabling only necessary permissions (net, inherited read/sys)
  • Explicitly disabling security-critical operations (run, write, ffi)
  • Restricting environment variables to a controlled subset
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for any security-related discussions or documentation
rg -l "worker.*permission" --type md
rg -l "deno.*permission" --type md

# Check for similar worker permission patterns
ast-grep --pattern 'new Worker($_, {
  $$$
  permissions: {
    $$$
  }
  $$$
})'

Length of output: 159


Script:

#!/bin/bash
# Look for Worker-related code and configurations
rg -l "new Worker\(" 
rg "permissions.*{" -A 10 

# Check for security documentation
fd "SECURITY.md|security.md"
cat README.md 2>/dev/null | grep -i "security\|permission"

# Look for Deno worker patterns
rg "Deno\..*Worker"

Length of output: 612


Script:

#!/bin/bash
# Read security documentation
cat SECURITY.md

# Check all worker implementations
cat src/typegate/src/runtimes/patterns/worker_manager/wasm.ts
cat src/typegate/src/runtimes/patterns/worker_manager/deno.ts
cat src/typegate/src/runtimes/deno/hooks/mod.ts

# Look for permission patterns in these specific files
rg "permissions" src/typegate/src/runtimes/patterns/worker_manager/wasm.ts src/typegate/src/runtimes/patterns/worker_manager/deno.ts src/typegate/src/runtimes/deno/hooks/mod.ts

Length of output: 6410

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

♻️ Duplicate comments (1)
src/typegate/src/runtimes/patterns/worker_manager/pooling.ts (1)

81-85: 🛠️ Refactor suggestion

Enhance queue cleanup to prevent memory leaks.

The current implementation only clears the timer but doesn't clear the queue entries. This could lead to memory leaks from lingering consumer and cancellation handler references.

Consider enhancing the cleanup:

  clear() {
    if (this.#timerId != null) {
      clearTimeout(this.#timerId);
    }
+   // Clear queue and invoke cancellation handlers
+   while (this.#queue.length > 0) {
+     this.#cancelNextEntry();
+   }
  }
🧹 Nitpick comments (8)
src/typegate/src/runtimes/wit_wire/mod.ts (5)

14-20: Use a dedicated interface for initialization parameters
Accepting a single object for initialization improves readability. Consider defining a named interface or type for params to enhance type clarity and consistency across the codebase.


21-31: Remove the unused _res variable or use it meaningfully
The _res variable from Meta.wit_wire.init is stored but never used. Eliminate dead code or utilize the response to prevent confusion.

      const _res = await Meta.wit_wire.init(
        componentPath,
        id,
        {
          expected_ops: ops,
          metatype_version: METATYPE_VERSION,
        },
        hostcall,
      );
-      return new WitWireHandle(id, componentPath, ops);
+      // If _res isn't needed, remove it or use it meaningfully.
      return new WitWireHandle(id, componentPath, ops);

52-52: Constructor is empty
The empty constructor is valid, but consider removing it if no custom initialization is required. A default constructor is implicit.

-  ) {}
+  ) {
+    // If no custom initialization is needed, omit the body entirely.
+  }

77-77: Consider a more explicit check
Relying on typeof res === 'string' works but could mask unexpected conditions. A more robust approach is to validate if res indeed holds expected fields.


154-159: Refine error code assignment
Wrapping error details in a dynamic object is flexible but might raise maintainability concerns. Consider introducing a well-defined error code enumeration for clarity.

tests/runtimes/python/python_test.ts (3)

13-13: Check path consistency
This relative import is valid but ensure consistency with any barrel files or aliases used in the project.


49-52: Type safety for resolver arguments
Casting to ResolverArgs via as unknown may bypass type checks. If possible, provide a properly typed object to catch errors at compile time.


87-87: Same typing issue
As with the previous lambda test, ensure stronger type safety by avoiding as unknown.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6a61cce and 6ff2bcd.

📒 Files selected for processing (5)
  • src/typegate/src/runtimes/deno/deno.ts (5 hunks)
  • src/typegate/src/runtimes/patterns/worker_manager/pooling.ts (4 hunks)
  • src/typegate/src/runtimes/wasm/worker.ts (1 hunks)
  • src/typegate/src/runtimes/wit_wire/mod.ts (8 hunks)
  • tests/runtimes/python/python_test.ts (12 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/typegate/src/runtimes/wasm/worker.ts
  • src/typegate/src/runtimes/deno/deno.ts
⏰ Context from checks skipped due to timeout of 90000ms (6)
  • GitHub Check: lint-compat (macos-14, aarch64-apple-darwin, false)
  • GitHub Check: lint-compat (macos-13, x86_64-apple-darwin, false)
  • GitHub Check: bulid-docker (linux/arm64, custom-arm)
  • GitHub Check: test-full
  • GitHub Check: bulid-docker (linux/amd64, custom-ubuntu-large)
  • GitHub Check: pre-commit
🔇 Additional comments (31)
src/typegate/src/runtimes/wit_wire/mod.ts (9)

33-33: Initialization return is clear
Returning the new WitWireHandle instance is straightforward and aligns with the static factory pattern.


56-56: Destructuring fields is concise
Accessing id, componentPath, and ops through destructuring is neat and improves readability.


60-60: Ensure JSON.stringify doesn't throw
If inJson can contain circular references, JSON.stringify will throw. Consider adding checks or a safer serialization approach.


71-71: Detailed cause information
Including componentPath in the error cause is helpful for debugging. Good practice.


85-86: Ops and component are captured
Storing ops and component in the error cause fosters better debugging context.


95-95: Consistent error cause
Good consistency in adding component to the error’s cause here and in preceding blocks.


108-108: Logging the component path
Continuing the same debugging pattern for any error scenario is commendable.


119-119: Consistent error structure
Retaining component within the final fallback error clarifies debugging.


133-133: Exported hostcall
Exporting hostcall for external usage expands flexibility. Ensure that inputs are validated or sanitized if json can come from untrusted sources.

tests/runtimes/python/python_test.ts (18)

6-10: New WitWire imports
Switching from a monolithic import to individual exports clarifies usage. Ensure references align with the new runtime structure.


15-27: Inline WitWire initialization is well-encapsulated
Defining a helper function (initInlineWitWire) keeps the setup code DRY and maintainable.


31-31: Correct usage of initInlineWitWire
The usage here is straightforward, properly passing parameters for initialization.


69-69: Reusing the helper
Re-initializing with initInlineWitWire for a different test scenario maintains consistency.


108-108: Engine initialization for tests
Spawning an engine with a specific Python runtime is correct for the test’s scope.


179-179: Inline chain usage
Chaining .on(e) config in your test queries is a succinct approach and is consistent with the overall test style.


182-184: Pre-warming approach is beneficial
This technique helps measure subsequent test performance more accurately after any cold starts.


276-276: Python engine usage
Using .engine("runtimes/python/python.py") again is consistent.


351-351: Reload engine
Re-initializing the engine with python.ts is valid for verifying reload behaviors.


361-361: Descriptive test name
Explicitly mentioning "no artifacts in sync mode" clarifies the test objective.


365-365: Testing no-artifact scenario
Creating an engine with "python_no_artifact.py" ensures coverage of minimal artifact usage.


371-374: GQL query structure
The minimal query is appropriate for verifying lambda calls in a no-artifact scenario.


396-404: Multiple fields in a single query
Verifying identityDef and identityLambda in one query is an efficient approach to cover multiple resolvers.


406-406: Empty line
No issues.


425-425: Clear test labeling
Identifies the focus on duplicate artifact uploads.


429-429: Python duplicate artifact test
Spanning a separate .py file ensures coverage of multi-artifact scenarios.


435-439: GraphQL request for duplicates
Checking two similarly structured queries in one request ensures the duplication logic is validated.


462-472: Extensive field checks
Including identityMod and identityModDuplicate within the same query helps verify correct artifact resolution.

src/typegate/src/runtimes/patterns/worker_manager/pooling.ts (4)

41-41: LGTM! Empty implementation is appropriate.

The empty clear() implementation is correct since the queue array is function-scoped and will be garbage collected naturally.


223-223: LGTM! Using forEach is more appropriate.

Good change from map to forEach since we're not using the return value of the iteration.


24-24: LGTM! Note the breaking change.

The addition of the clear() method to the WaitQueue interface is appropriate for resource cleanup. Be aware that this is a breaking change requiring all implementations to provide this method.

Let's verify if there are any other implementations of WaitQueue that need to be updated:

✅ Verification successful

Breaking change is properly implemented

The addition of clear() method to the WaitQueue interface is safe. All existing implementations already provide this method:

  • createSimpleWaitQueue: implements empty clear()
  • WaitQueueWithTimeout: implements clear() with proper resource cleanup (uses using keyword in tests)
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for other WaitQueue implementations
ast-grep --pattern 'class $_ implements WaitQueue'

Length of output: 52


Script:

#!/bin/bash
# First, find files containing WaitQueue
rg "WaitQueue" --type ts -l

# Then look for implementations with different patterns
ast-grep --pattern 'implements WaitQueue'
ast-grep --pattern 'class $_ implements WaitQueue'
ast-grep --pattern 'const $_ = createSimpleWaitQueue'

Length of output: 287


Script:

#!/bin/bash
# Check content of both files
echo "=== pooling.ts ==="
rg "WaitQueue" -C 5 src/typegate/src/runtimes/patterns/worker_manager/pooling.ts

echo -e "\n=== pooling_test.ts ==="
rg "WaitQueue" -C 5 tests/patterns/worker_manager/pooling_test.ts

Length of output: 2504


225-225: Verify race condition handling during cleanup.

While adding wait queue cleanup is good, verify that there's no race condition between destroying workers and clearing the wait queue. Consider if we need to handle in-flight worker requests.

Let's analyze the worker lifecycle handling:

✅ Verification successful

Implementation is safe from race conditions

The worker lifecycle implementation safely handles cleanup by:

  • Only destroying idle workers during clear operation
  • Maintaining separate tracking of busy workers
  • Protecting in-flight requests through the worker borrowing mechanism
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for worker lifecycle management patterns
rg -A 5 "worker\.(destroy|terminate|close)" --type ts

Length of output: 2419


Script:

#!/bin/bash
# Search for wait queue implementation and worker state management
echo "=== Wait Queue Implementation ==="
ast-grep --pattern 'class WaitQueue {
  $$$
}'

echo -e "\n=== Worker State Management ==="
rg -B 5 -A 10 "class PoolingWorkerManager" --type ts

echo -e "\n=== Request Handling ==="
rg -B 2 -A 5 "execute\(" --type ts

Length of output: 7526


Script:

#!/bin/bash
# Get the complete implementation of pooling worker manager
echo "=== Pooling Worker Manager Implementation ==="
cat src/typegate/src/runtimes/patterns/worker_manager/pooling.ts

echo -e "\n=== Worker Interface ==="
rg -B 2 -A 5 "interface Worker" --type ts

Length of output: 6338

Possible race condition so it is not guaranteed that there will be a
shifted item.
Copy link

codecov bot commented Jan 29, 2025

Codecov Report

Attention: Patch coverage is 84.17508% with 47 lines in your changes missing coverage. Please review.

Project coverage is 77.77%. Comparing base (30d8b1e) to head (af729a7).
Report is 3 commits behind head on main.

Files with missing lines Patch % Lines
src/typegate/src/runtimes/wit_wire/mod.ts 47.82% 12 Missing ⚠️
src/typegate/src/runtimes/substantial/agent.ts 69.69% 10 Missing ⚠️
src/typegate/src/runtimes/deno/deno.ts 46.66% 8 Missing ⚠️
src/typegate/src/runtimes/substantial.ts 37.50% 5 Missing ⚠️
...egate/src/runtimes/patterns/worker_manager/deno.ts 33.33% 4 Missing ⚠️
...egate/src/runtimes/patterns/worker_manager/wasm.ts 93.61% 3 Missing ⚠️
...pegate/src/runtimes/patterns/worker_manager/mod.ts 71.42% 2 Missing ⚠️
src/typegate/src/config/types.ts 87.50% 1 Missing ⚠️
...te/src/runtimes/patterns/worker_manager/pooling.ts 93.33% 1 Missing ⚠️
src/typegate/src/runtimes/wasm/worker_manager.ts 98.59% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #966      +/-   ##
==========================================
- Coverage   78.04%   77.77%   -0.27%     
==========================================
  Files         157      160       +3     
  Lines       19283    19657     +374     
  Branches     1945     1965      +20     
==========================================
+ Hits        15049    15289     +240     
- Misses       4211     4347     +136     
+ Partials       23       21       -2     

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

@luckasRanarison luckasRanarison merged commit f96ade2 into main Jan 29, 2025
12 of 13 checks passed
@luckasRanarison luckasRanarison deleted the met-805-wasm-worker-manager branch January 29, 2025 10:03
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.

3 participants