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: add compensation feature to deno context and utils #945

Open
wants to merge 20 commits into
base: main
Choose a base branch
from

Conversation

j03-dev
Copy link
Contributor

@j03-dev j03-dev commented Dec 19, 2024

Add compensation && utils feature to deno context

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 compensation functionality to handle transaction failures and rollback operations.
    • Introduced utility methods for generating UUIDs, random numbers, and timestamps.
    • Enhanced workflow context with compensation stack and error handling.
  • Protocol Updates

    • Added new Compensation message type to capture detailed error and compensation information.
    • Extended Event message to support compensation-related data.
  • Type Definitions

    • Updated TypeScript type signatures to support more comprehensive error and operation handling.
    • Expanded OperationEvent type with additional compensation details.
  • Tests

    • Added new test cases to validate compensation processes for account balances.
  • Chores

    • Added .helix/ to .gitignore.

Copy link

linear bot commented Dec 19, 2024

Copy link
Contributor

coderabbitai bot commented Jan 8, 2025

📝 Walkthrough

Walkthrough

This pull request introduces a comprehensive compensation mechanism across multiple components of the system. The changes span protocol definitions, Rust and TypeScript converters, runtime contexts, and test workflows. The core addition is a new Compensation message type that allows capturing detailed information about compensation events, including a save ID, error message, and compensation result. The implementation enables workflows to define compensation logic for transactions, providing a robust error handling and rollback strategy.

Changes

File Change Summary
src/substantial/protocol/events.proto Added Compensation message with save_id, error, and compensation_result fields; Updated Event message to include compensation field
src/substantial/src/converters.rs Modified OperationEvent::Compensate to include save_id, error, and compensation_result; Updated conversion logic for Event
src/substantial/src/protocol/events.rs Implemented Compensation message structure with standard protobuf traits; Updated Event message to include compensation field
src/typegate/engine/runtime.d.ts Updated type definitions for various interfaces, including OperationEvent with new compensation properties
src/typegate/src/runtimes/substantial/deno_context.ts Added Utils class with utility methods; Enhanced Context with compensationStack and compensation handling in save method
tests/runtimes/substantial/common.ts Added new test cases for starting and verifying compensation processes
tests/runtimes/substantial/imports/common_types.ts Enhanced Context and SaveOption interfaces with new properties and added Utils interface
tests/runtimes/substantial/substantial.py Added start_compensation entry to g.expose method for initiating compensation processes
tests/runtimes/substantial/workflows/workflow.ts Added compensationExample function demonstrating transaction compensation logic
.gitignore Added entry for .helix/ to ignore related files

Possibly related PRs

  • feat(metagen): client_ts #790: The changes in the main PR, which involve adding a new Compensation message type and modifying the Event message to include it, are related to the modifications in the retrieved PR that expand the OperationEvent enum to include a struct variant for compensation, as both involve handling compensation-related data structures.
  • feat: Unify worker manager #954: The changes in the main PR, which involve adding a new Compensation message type and modifying the Event message to include it, are related to the changes in the retrieved PR, which updates the OperationEvent enum to include a Compensate variant that utilizes the new Compensation fields in its conversion logic. Both PRs modify structures that handle compensation-related data.

Suggested reviewers

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

📜 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 9907f1e and c6376e6.

📒 Files selected for processing (2)
  • src/typegate/engine/runtime.d.ts (4 hunks)
  • tests/runtimes/substantial/common.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • tests/runtimes/substantial/common.ts
  • src/typegate/engine/runtime.d.ts

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.

@j03-dev j03-dev requested a review from michael-0acf4 January 8, 2025 08:59
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 (4)
src/typegate/src/runtimes/substantial/deno_context.ts (3)

140-140: Simplify the conditional check

Since compensationStack is always initialized as an array, the check compensationStack && is redundant. You can simplify the condition to:

Apply this diff:

- if (compensationStack && compensationStack.length) {
+ if (compensationStack.length) {
🧰 Tools
🪛 Biome (1.9.4)

[error] 140-140: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


143-143: Simplify the compensation function call

You can simplify await Promise.resolve(compensationFn()) to await compensationFn(). The await operator already handles both synchronous and asynchronous functions.

Apply this diff:

- const result = await Promise.resolve(compensationFn());
+ const result = await compensationFn();

509-513: Consider adding input validation to random(a, b)

Currently, the random method does not validate if a is less than or equal to b. Adding input validation can prevent potential errors when a > b.

You might consider adding a check like:

if (a > b) {
  throw new Error('Invalid arguments: a must be less than or equal to b');
}
.helix/languages.toml (1)

17-24: Consider enabling unstable APIs.

Since Deno often requires unstable APIs for certain features, consider adding the unstable flag to the configuration:

 [language-server.deno-lsp.config.deno]
 enable = true
+unstable = true
 suggest = { completeFunctionCalls = false, imports = { hosts = { "https://deno.land" = true } } }
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between c60f4ee and 6ccb771.

📒 Files selected for processing (10)
  • .helix/languages.toml (1 hunks)
  • src/substantial/protocol/events.proto (2 hunks)
  • src/substantial/src/converters.rs (3 hunks)
  • src/substantial/src/protocol/events.rs (11 hunks)
  • src/typegate/engine/runtime.d.ts (4 hunks)
  • src/typegate/src/runtimes/substantial/deno_context.ts (10 hunks)
  • tests/runtimes/substantial/common.ts (4 hunks)
  • tests/runtimes/substantial/imports/common_types.ts (2 hunks)
  • tests/runtimes/substantial/substantial.py (2 hunks)
  • tests/runtimes/substantial/workflows/workflow.ts (2 hunks)
🧰 Additional context used
🪛 Biome (1.9.4)
src/typegate/src/runtimes/substantial/deno_context.ts

[error] 140-140: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

⏰ Context from checks skipped due to timeout of 90000ms (5)
  • GitHub Check: lint-compat (macos-14, aarch64-apple-darwin, false)
  • GitHub Check: bulid-docker (linux/amd64, custom-ubuntu-large)
  • GitHub Check: lint-compat (macos-13, x86_64-apple-darwin, false)
  • GitHub Check: test-full
  • GitHub Check: pre-commit
🔇 Additional comments (12)
src/substantial/src/converters.rs (2)

70-74: Compensate variant is correctly defined

The new Compensate variant in OperationEvent is well-defined with appropriate fields, enhancing the handling of compensation events.


351-367: TryFrom<Operation> implementation correctly handles Compensate

The conversion logic for the Compensate event is properly implemented, ensuring all fields are accurately converted and serialized.

tests/runtimes/substantial/imports/common_types.ts (3)

51-51: Added utils property to Context interface

The utils property is appropriately added to the Context interface, providing utility methods for workflows.


83-84: Included compensateWith in SaveOption interface

The optional compensateWith function is correctly added to SaveOption, allowing for compensation logic in save operations.


86-89: Defined the Utils interface

The Utils interface is properly defined with the expected methods now, random, and uuid4, enhancing utility functionality.

src/substantial/protocol/events.proto (2)

34-38: Consider using a JSON string for compensation_result.

Similar to SaveResolved.json_result, consider documenting that the compensation_result field should contain a JSON-encoded string for consistency.


67-67: LGTM!

The new field compensation is correctly added to the Event message with an appropriate field number, and it's not part of the oneof group which allows it to coexist with other event types.

.helix/languages.toml (1)

1-14: LGTM!

The JavaScript and TypeScript language configurations are properly set up with Deno integration, including all necessary fields like shebangs, roots, file types, and language servers.

src/substantial/src/protocol/events.rs (1)

Line range hint 902-2426: LGTM! Generated code matches protocol definitions.

The generated Rust code correctly implements:

  • The new Compensation message with all fields
  • The Event message modifications
  • All necessary traits and methods

The file is properly marked as generated and should not be manually edited.

tests/runtimes/substantial/substantial.py (2)

34-34: LGTM! Import added for compensation feature.

The compensation example is correctly added to the list of imports.


88-95: LGTM! Compensation endpoint properly configured.

The compensation endpoint is well-structured with:

  • Proper type definition for the account parameter
  • Correct workflow name mapping
src/typegate/engine/runtime.d.ts (1)

325-330: LGTM! Compensation event type properly defined.

The Compensate event type is well-structured with all necessary fields:

  • save_id for tracking the operation
  • error for failure details
  • compensation_result for tracking the compensation outcome

Comment on lines +89 to +92
if (option?.retry?.compensationOnfristFail) {
await this.#triggerCompensation(id, err);
throw err;
}
Copy link
Contributor

@coderabbitai coderabbitai bot Jan 8, 2025

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix the typo in 'compensationOnfristFail' to 'compensationOnFirstFail'

There is a typo in the property name compensationOnfristFail. It should be compensationOnFirstFail throughout the code to reflect the correct spelling.

Apply this diff to correct the typo:

- compensationOnfristFail
+ compensationOnFirstFail

Also applies to: 385-385

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, you're right

Copy link
Contributor

Choose a reason for hiding this comment

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

@j03-dev Thanks for confirming! This will improve the code readability.

(_/)
(^.^)
(")_(")


If you found this review helpful, would you consider giving us a shout-out on X?
Thank you for using CodeRabbit!

src/typegate/src/runtimes/substantial/deno_context.ts Outdated Show resolved Hide resolved
tests/runtimes/substantial/workflows/workflow.ts Outdated Show resolved Hide resolved
tests/runtimes/substantial/common.ts Outdated 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

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 6ccb771 and 6d2f9ba.

📒 Files selected for processing (2)
  • tests/runtimes/substantial/common.ts (2 hunks)
  • tests/runtimes/substantial/workflows/workflow.ts (2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (5)
  • GitHub Check: test-full
  • 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: pre-commit
🔇 Additional comments (3)
tests/runtimes/substantial/workflows/workflow.ts (2)

176-181: ⚠️ Potential issue

Fix compensation amount mismatch.

The compensation amount should match the debit amount. Currently, it debits 2 but credits 4.

Apply this diff:

   await ctx.save(() => {
-    debitAccount(2);
+    const debitAmount = 2;
+    debitAccount(account, debitAmount);
     risky_transaction();
   }, {
-    compensateWith: () => creditAccount(4),
+    compensateWith: () => creditAccount(account, debitAmount),
   });

Likely invalid or redundant comment.


156-166: 🛠️ Refactor suggestion

Move helper functions outside for reusability and testing.

The helper functions should be moved outside the main function to improve reusability and testability.

Apply this diff:

+const debitAccount = (account: number, value: number) => {
+  if (account < value) {
+    throw new Error(`Insufficient balance: ${account} < ${value}`);
+  }
+  return account - value;
+};
+
+const creditAccount = (account: number, value: number) => {
+  return account + value;
+};
+
+const risky_transaction = () => {
+  throw Error("Transaction Failed");
+};
+
 export async function compensation(ctx: Context) {
   const { account } = ctx.kwargs;
-
-  const debitAccount = (value: number) => {
-    return account - value;
-  };
-
-  const creditAccount = (value: number) => {
-    return account + value;
-  };
-
-  const risky_transaction = () => {
-    throw Error("Transaction Failed");
-  };

Likely invalid or redundant comment.

tests/runtimes/substantial/common.ts (1)

639-680: LGTM!

The implementation of the filter test case is correct and comprehensive.

tests/runtimes/substantial/workflows/workflow.ts Outdated Show resolved Hide resolved
Comment on lines 158 to 168
const account_balance = 1000;

await t.should("compensate account balance", async () => {
await gql`
mutation {
start_compensation(kwargs: { account: $account_balance })
}
`
.withVars({ account_balance })
.on(e);
});
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Improve test coverage for compensation workflow.

The current test only verifies the initial state. Consider adding:

  1. Verification of compensation workflow execution
  2. Verification of intermediate states and error handling

Add the following test cases:

// Add after line 168
await t.should("verify compensation workflow execution", async () => {
  await gql`
    query {
      results(name: "compensation") {
        completed {
          runs {
            result {
              status
              value
            }
          }
        }
      }
    }
  `
  .expectData({
    results: {
      completed: {
        runs: [{
          result: {
            status: "COMPLETED_WITH_ERROR",
            value: "Transaction Failed"
          }
        }]
      }
    }
  })
  .on(e);
});

await t.should("verify account state after compensation", async () => {
  await gql`
    query {
      results(name: "compensation") {
        completed {
          runs {
            events {
              type
              compensation {
                save_id
                error
                compensation_result
              }
            }
          }
        }
      }
    }
  `
  .expectBody((body) => {
    const events = body.data.results.completed.runs[0].events;
    const compensationEvents = events.filter(
      (e: any) => e.type === "compensation"
    );
    assertEquals(compensationEvents.length > 0, true);
    assertEquals(
      compensationEvents.every((e: any) => e.compensation.compensation_result === 1000),
      true,
      "Account balance not restored after compensation"
    );
  })
  .on(e);
});

Comment on lines 1 to 10
[[language]]
name = "javascript"
shebangs = ["deno"]
roots = ["deno.json", "deno.jsonc"]
file-types = ["js"]
language-servers = ["deno-lsp"]
auto-format = true
[[language]]
name = "typescript"
shebangs = ["deno"]
Copy link
Contributor

Choose a reason for hiding this comment

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

is this required?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

no , its just for helix (editor) like .vscode ... , i'll remove this ...

Comment on lines 160 to 168
await t.should("compensate account balance", async () => {
await gql`
mutation {
start_compensation(kwargs: { account: $account_balance })
}
`
.withVars({ account_balance })
.on(e);
});
Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't this expect an error?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yeah

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 (4)
tests/runtimes/substantial/workflows/workflow.ts (2)

153-167: 🛠️ Refactor suggestion

Move helper functions outside for better reusability and testability.

The helper functions should be moved outside the main function to improve code organization and enable unit testing.

Apply this diff:

+const debitAccount = (account: number, value: number) => {
+  return account - value;
+};
+
+const creditAccount = (account: number, value: number) => {
+  return account + value;
+};
+
+const risky_transaction = () => {
+  throw Error("Transaction Failed");
+};
+
 export async function compensation(ctx: Context) {
   const { account } = ctx.kwargs;
-
-  const debitAccount = (value: number) => {
-    return account - value;
-  };
-
-  const creditAccount = (value: number) => {
-    return account + value;
-  };
-
-  const risky_transaction = () => {
-    throw Error("Transaction Failed");
-  };

168-170: 🛠️ Refactor suggestion

Add balance validation and consistent assertions.

The first transaction includes an assertion but others don't. Also, balance validation is missing.

Add balance validation and consistent assertions:

+  const validateTransaction = (balance: number, amount: number) => {
+    assertEquals(typeof amount, 'number', 'Amount must be a number');
+    assertEquals(amount > 0, true, 'Amount must be positive');
+    assertEquals(balance >= amount, true, 'Insufficient balance');
+  };

   await ctx.save(() => {
+    validateTransaction(account, 4);
     debitAccount(4)
   }, {
     compensateWith: () => [creditAccount(4), assertEquals(account, 1000)],
   });
src/typegate/src/runtimes/substantial/deno_context.ts (1)

385-385: 🛠️ Refactor suggestion

Fix the typo in 'compensationOnfristFail'.

The property name has a typo.

Apply this diff:

-    compensationOnfristFail: boolean;
+    compensationOnFirstFail: boolean;
tests/runtimes/substantial/common.ts (1)

168-177: 🛠️ Refactor suggestion

Enhance test coverage for compensation workflow.

The current test only verifies the error case. Add tests for successful compensation and intermediate states.

Add these test cases:

await t.should("verify compensation workflow execution", async () => {
  await gql`
    query {
      results(name: "compensation") {
        completed {
          runs {
            result {
              status
              value
            }
          }
        }
      }
    }
  `
  .expectData({
    results: {
      completed: {
        runs: [{
          result: {
            status: "COMPLETED_WITH_ERROR",
            value: "Transaction Failed"
          }
        }]
      }
    }
  })
  .on(e);
});

await t.should("verify account state after compensation", async () => {
  await gql`
    query {
      results(name: "compensation") {
        completed {
          runs {
            events {
              type
              compensation {
                save_id
                error
                compensation_result
              }
            }
          }
        }
      }
    }
  `
  .expectBody((body) => {
    const events = body.data.results.completed.runs[0].events;
    const compensationEvents = events.filter(
      (e: any) => e.type === "compensation"
    );
    assertEquals(compensationEvents.length > 0, true);
    assertEquals(
      compensationEvents.every((e: any) => e.compensation.compensation_result === 1000),
      true,
      "Account balance not restored after compensation"
    );
  })
  .on(e);
});
🧹 Nitpick comments (4)
tests/runtimes/substantial/workflows/workflow.ts (2)

172-174: Add missing assertions to remaining transactions.

For consistency, all transactions should include balance assertions in their compensation handlers.

Apply this diff:

   await ctx.save(() => debitAccount(10), {
-    compensateWith: () => creditAccount(10),
+    compensateWith: () => [creditAccount(10), assertEquals(account, 1000)],
   });

   await ctx.save(() => debitAccount(100), {
-    compensateWith: () => creditAccount(100),
+    compensateWith: () => [creditAccount(100), assertEquals(account, 1000)],
   });

Also applies to: 183-185


176-181: Fix potential race condition in account updates.

The current implementation might lead to race conditions as account balance is shared state. Consider using atomic operations or a proper transaction mechanism.

Consider these improvements:

  1. Use a proper transaction manager to handle atomic operations
  2. Implement optimistic locking
  3. Add version control to detect concurrent modifications

Would you like me to provide an example implementation?

src/typegate/src/runtimes/substantial/deno_context.ts (2)

140-140: Use optional chaining for better readability.

The condition can be simplified using optional chaining.

Apply this diff:

-    if (compensationStack && compensationStack.length) {
+    if (compensationStack?.length) {
🧰 Tools
🪛 Biome (1.9.4)

[error] 140-140: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


502-518: Improve Utils class implementation.

The Utils class implementation could be improved for better error handling and type safety.

Consider these improvements:

  1. Add input validation for the random method
  2. Add error handling for UUID generation
  3. Add proper typing for return values
 class Utils {
   constructor(private ctx: Context) {}

   async now() {
     return await this.ctx.save(() => new Date());
   }

   async random(a: number, b: number) {
+    if (typeof a !== 'number' || typeof b !== 'number') {
+      throw new TypeError('Arguments must be numbers');
+    }
+    if (a > b) {
+      throw new Error('First argument must be less than or equal to second argument');
+    }
     return await this.ctx.save(() =>
       Math.floor(Math.random() * (b - a + 1)) + a
     );
   }

   async uuid4() {
+    try {
       return await this.ctx.save(() => randomUUID());
+    } catch (error) {
+      throw new Error(`Failed to generate UUID: ${error.message}`);
+    }
   }
 }
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 6d2f9ba and a2e4bd9.

📒 Files selected for processing (3)
  • src/typegate/src/runtimes/substantial/deno_context.ts (10 hunks)
  • tests/runtimes/substantial/common.ts (1 hunks)
  • tests/runtimes/substantial/workflows/workflow.ts (2 hunks)
🧰 Additional context used
🪛 Biome (1.9.4)
src/typegate/src/runtimes/substantial/deno_context.ts

[error] 140-140: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

⏰ Context from checks skipped due to timeout of 90000ms (5)
  • GitHub Check: lint-compat (macos-14, aarch64-apple-darwin, false)
  • GitHub Check: bulid-docker (linux/amd64, custom-ubuntu-large)
  • GitHub Check: lint-compat (macos-13, x86_64-apple-darwin, false)
  • GitHub Check: test-full
  • GitHub Check: pre-commit

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 (2)
tests/runtimes/substantial/workflows/workflow.ts (2)

158-168: 🛠️ Refactor suggestion

Move helper functions outside the main function.

Helper functions should be pure and moved outside the main function for better reusability and testing.

+const debitAccount = (account: number, value: number) => {
+  return account - value;
+};
+
+const creditAccount = (account: number, value: number) => {
+  return account + value;
+};
+
+const risky_transaction = () => {
+  throw Error("Transaction Failed");
+};
+
 export async function compensationExample(ctx: Context) {
   const { account } = ctx.kwargs;
-
-  const debitAccount = (value: number) => {
-    return account - value;
-  };
-
-  const creditAccount = (value: number) => {
-    return account + value;
-  };
-
-  const risky_transaction = () => {
-    throw Error("Transaction Failed");
-  };

170-190: 🛠️ Refactor suggestion

Add consistent balance validation and assertions across all transactions.

The transactions lack proper balance validation and have inconsistent assertions. Only the first transaction includes an assertion.

  1. Add a validation helper:
const validateTransaction = (balance: number, amount: number) => {
  assertEquals(typeof amount, 'number', 'Amount must be a number');
  assertEquals(amount > 0, true, 'Amount must be positive');
  assertEquals(balance >= amount, true, 'Insufficient balance');
};
  1. Apply consistent validation and assertions:
   await ctx.save(() => {
+    validateTransaction(account, 4);
-    debitAccount(4)
+    return debitAccount(account, 4);
   }, {
-    compensateWith: () => {
-      creditAccount(4);
-      assertEquals(account, 1000);
-    },
+    compensateWith: () => [creditAccount(account, 4), assertEquals(account, 1000)],
   });

   await ctx.save(() => {
+    validateTransaction(account, 10);
-    debitAccount(10)
+    return debitAccount(account, 10);
   }, {
-    compensateWith: () => creditAccount(10),
+    compensateWith: () => [creditAccount(account, 10), assertEquals(account, 1000)],
   });

   await ctx.save(() => {
+    validateTransaction(account, 2);
-    debitAccount(2);
+    const newBalance = debitAccount(account, 2);
     risky_transaction();
+    return newBalance;
   }, {
-    compensateWith: () => creditAccount(2),
+    compensateWith: () => [creditAccount(account, 2), assertEquals(account, 1000)],
   });

   await ctx.save(() => {
+    validateTransaction(account, 100);
-    debitAccount(100)
+    return debitAccount(account, 100);
   }, {
-    compensateWith: () => creditAccount(100),
+    compensateWith: () => [creditAccount(account, 100), assertEquals(account, 1000)],
   });
🧹 Nitpick comments (3)
tests/runtimes/substantial/imports/common_types.ts (2)

84-84: Consider using a more specific return type for compensateWith.

The any return type loses type safety. Consider defining a more specific type that represents the expected compensation result.

-  compensateWith?: () => any | Promise<any>;
+  compensateWith?: () => CompensationResult | Promise<CompensationResult>;

Where CompensationResult could be defined as:

type CompensationResult = {
  success: boolean;
  message?: string;
  data?: unknown;
};

87-90: Add JSDoc comments to document the Utils interface.

The interface methods would benefit from documentation, especially the random method's parameters and the range behavior.

 export interface Utils {
+  /** Returns the current date and time */
   now: () => Promise<Date>;
+  /** Returns a random number between a (inclusive) and b (exclusive) */
   random: (a: number, b: number) => Promise<number>;
+  /** Generates a random UUID v4 string */
   uuid4: () => Promise<string>;
 }
tests/runtimes/substantial/workflows/workflow.ts (1)

155-156: Add JSDoc documentation and type safety.

Add documentation explaining the purpose of this example and type safety for the account parameter.

+/**
+ * Example demonstrating compensation mechanism in workflows.
+ * Shows how to handle transaction rollbacks when operations fail.
+ * @param ctx Context object containing workflow parameters
+ * @param ctx.kwargs.account {number} The account balance to operate on
+ */
-export async function compensationExample(ctx: Context) {
+export async function compensationExample(ctx: Context & { kwargs: { account: number } }) {
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 5ad4e4f and 9907f1e.

⛔ Files ignored due to path filters (1)
  • .ghjk/deno.lock is excluded by !**/*.lock
📒 Files selected for processing (4)
  • tests/runtimes/substantial/common.ts (2 hunks)
  • tests/runtimes/substantial/imports/common_types.ts (2 hunks)
  • tests/runtimes/substantial/substantial.py (2 hunks)
  • tests/runtimes/substantial/workflows/workflow.ts (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • tests/runtimes/substantial/substantial.py
  • tests/runtimes/substantial/common.ts
⏰ Context from checks skipped due to timeout of 90000ms (5)
  • GitHub Check: test-full
  • 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: pre-commit
🔇 Additional comments (2)
tests/runtimes/substantial/imports/common_types.ts (2)

50-51: LGTM! Well-structured interface extensions.

The addition of logger and utils properties to the Context interface provides a clean way to access logging and utility functions.


Line range hint 4-7: Track TODOs in the issue system.

The TODO comments lack specificity and should be tracked in the issue system:

  1. "include this as part of the metagen generated code"
  2. "merge these"

Please create corresponding issues and update these comments with the issue references.

Would you like me to help create these issues with detailed descriptions?

@@ -78,7 +79,15 @@ export interface SaveOption {
minBackoffMs: number;
maxBackoffMs: number;
maxRetries: number;
compensationOnfristFail: boolean;
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix typo in property name.

The property name contains a typo: compensationOnfristFail should be compensationOnFirstFail.

-    compensationOnfristFail: boolean;
+    compensationOnFirstFail: boolean;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
compensationOnfristFail: boolean;
compensationOnFirstFail: boolean;

@@ -75,6 +77,7 @@ export async function retryExample(ctx: Context) {
minBackoffMs: 1000,
maxBackoffMs: 5000,
maxRetries: 4,
compensationOnfristFail: false,
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix typo in retry configuration property name.

The property name compensationOnfristFail contains a typo. It should be compensationOnFirstFail.

-        compensationOnfristFail: false,
+        compensationOnFirstFail: false,

Also applies to: 100-100

Copy link

codecov bot commented Feb 3, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 77.83%. Comparing base (f027067) to head (6b81690).

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #945      +/-   ##
==========================================
+ Coverage   77.77%   77.83%   +0.06%     
==========================================
  Files         160      160              
  Lines       19657    19711      +54     
  Branches     1964     1964              
==========================================
+ Hits        15289    15343      +54     
  Misses       4347     4347              
  Partials       21       21              

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

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