Skip to content

Conversation

@adityachoudhari26
Copy link
Contributor

@adityachoudhari26 adityachoudhari26 commented May 28, 2025

Summary by CodeRabbit

  • New Features

    • Added support for specifying and managing "exit hooks" when creating or updating deployments via the API. Users can now include an array of exit hooks, each with a name, job agent, and configuration, as part of deployment operations.
  • Bug Fixes

    • Improved database schema to enforce uniqueness for hooks and runbooks, reducing potential data duplication issues.
  • Chores

    • Commented out all code related to resource deployment rules, making it inactive but still present in the codebase.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented May 28, 2025

Walkthrough

This change introduces support for "exit hooks" in deployment creation and update workflows. It adds an exitHooks array property to relevant OpenAPI schemas, request handlers, and database schema definitions. New utility logic and unique indexes ensure proper upsert and uniqueness for exit hooks and associated runbooks. Related code and database migrations are included.

Changes

File(s) Change Summary
apps/webservice/src/app/api/v1/deployments/[deploymentId]/openapi.ts,
apps/webservice/src/app/api/v1/deployments/openapi.ts,
openapi.v1.json
Added ExitHook schema; extended deployment POST/PATCH request bodies to accept exitHooks array.
apps/webservice/src/app/api/v1/deployments/[deploymentId]/route.ts,
apps/webservice/src/app/api/v1/deployments/route.ts
Updated POST and PATCH handlers to process exitHooks array with sequential upsert logic.
apps/webservice/src/app/api/v1/deployments/_utils/upsertExitHook.ts Introduced utility for upserting exit hooks and related runbook/runhook records within a transaction.
packages/db/drizzle/0107_small_deathbird.sql,
packages/db/drizzle/meta/_journal.json
Added unique indexes for hook and runbook tables; recorded migration in journal.
packages/db/src/schema/deployment.ts Extended deployment schema to include optional exitHooks array.
packages/db/src/schema/event.ts Refactored hook table schema to add a unique index on (name, scopeType, scopeId).
packages/db/src/schema/runbook.ts Refactored runbook table schema to add a unique index on (name, systemId).
packages/db/src/schema/resource-deployment-rule.ts Entire file commented out, disabling all resource deployment rule logic and exports.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant API
    participant DB
    participant UpsertExitHook

    Client->>API: POST/PATCH /v1/deployments (with exitHooks)
    API->>DB: Create/Update deployment (transaction)
    alt exitHooks present
        API->>UpsertExitHook: For each exitHook in exitHooks
        UpsertExitHook->>DB: Upsert hook, runbook, runhook, variables (transactional)
    end
    API-->>Client: Response
Loading

Possibly related PRs

Poem

A rabbit hopped through fields of code,
Planting hooks where deployments strode.
With indexes neat and schemas new,
Exit hooks now join the crew!
Each upsert blooms in database light—
Deployments exit, all is right.
🐇✨


📜 Recent review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6c9dbe5 and b636c29.

📒 Files selected for processing (1)
  • openapi.v1.json (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • openapi.v1.json
⏰ Context from checks skipped due to timeout of 90000ms (5)
  • GitHub Check: build (linux/amd64)
  • GitHub Check: Typecheck
  • GitHub Check: build (linux/amd64)
  • GitHub Check: Lint
  • GitHub Check: build (linux/amd64)

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
🪧 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.
    • Explain this complex logic.
    • 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 explain this code block.
    • @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 explain its main purpose.
    • @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.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

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.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @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.

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.

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 (2)
openapi.v1.json (2)

679-684: Make exitHooks nullable if null should be allowed
To explicitly allow null values for the exitHooks array—aligning with other nullable properties in the schema—add "nullable": true to this property.


4926-4954: Enhance ExitHook schema clarity
Consider adding an object-level "description" and setting "additionalProperties": false for the ExitHook schema to clarify the contract and prevent unexpected fields.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1314648 and 03237c1.

📒 Files selected for processing (12)
  • apps/webservice/src/app/api/v1/deployments/[deploymentId]/openapi.ts (1 hunks)
  • apps/webservice/src/app/api/v1/deployments/[deploymentId]/route.ts (2 hunks)
  • apps/webservice/src/app/api/v1/deployments/_utils/upsertExitHook.ts (1 hunks)
  • apps/webservice/src/app/api/v1/deployments/openapi.ts (2 hunks)
  • apps/webservice/src/app/api/v1/deployments/route.ts (4 hunks)
  • openapi.v1.json (3 hunks)
  • packages/db/drizzle/0107_small_deathbird.sql (1 hunks)
  • packages/db/drizzle/meta/_journal.json (1 hunks)
  • packages/db/src/schema/deployment.ts (1 hunks)
  • packages/db/src/schema/event.ts (1 hunks)
  • packages/db/src/schema/resource-deployment-rule.ts (1 hunks)
  • packages/db/src/schema/runbook.ts (2 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
`**/*.{ts,tsx}`: **Note on Error Handling:** Avoid strict enforcement of try/catch blocks. Code may use early returns, Promise chains (.then().catch()), or other patterns for error...

**/*.{ts,tsx}: Note on Error Handling:
Avoid strict enforcement of try/catch blocks. Code may use early returns, Promise chains (.then().catch()), or other patterns for error handling. These are acceptable as long as they maintain clarity and predictability.

  • apps/webservice/src/app/api/v1/deployments/[deploymentId]/route.ts
  • apps/webservice/src/app/api/v1/deployments/route.ts
  • packages/db/src/schema/resource-deployment-rule.ts
  • packages/db/src/schema/event.ts
  • apps/webservice/src/app/api/v1/deployments/[deploymentId]/openapi.ts
  • packages/db/src/schema/deployment.ts
  • apps/webservice/src/app/api/v1/deployments/openapi.ts
  • packages/db/src/schema/runbook.ts
  • apps/webservice/src/app/api/v1/deployments/_utils/upsertExitHook.ts
🧬 Code Graph Analysis (4)
apps/webservice/src/app/api/v1/deployments/[deploymentId]/route.ts (2)
apps/webservice/src/app/api/v1/deployments/_utils/upsertExitHook.ts (1)
  • upsertExitHook (80-90)
packages/db/src/client.ts (1)
  • db (15-15)
apps/webservice/src/app/api/v1/deployments/route.ts (1)
apps/webservice/src/app/api/v1/deployments/_utils/upsertExitHook.ts (1)
  • upsertExitHook (80-90)
packages/db/src/schema/runbook.ts (1)
packages/db/src/schema/job-agent.ts (1)
  • jobAgent (10-22)
apps/webservice/src/app/api/v1/deployments/_utils/upsertExitHook.ts (4)
packages/db/src/common.ts (3)
  • Tx (22-22)
  • buildConflictUpdateColumns (30-46)
  • takeFirst (9-13)
packages/db/src/schema/deployment.ts (2)
  • deployment (69-93)
  • Deployment (117-117)
packages/db/src/schema/event.ts (1)
  • hook (30-46)
packages/db/src/schema/runbook.ts (1)
  • runbook (20-38)
⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: Typecheck
  • GitHub Check: Lint
  • GitHub Check: build (linux/amd64)
  • GitHub Check: build (linux/amd64)
🔇 Additional comments (17)
packages/db/drizzle/meta/_journal.json (1)

754-760: LGTM! Standard migration journal entry.

The new journal entry follows the correct Drizzle migration format and properly tracks the database schema changes for the exit hooks feature.

packages/db/src/schema/deployment.ts (1)

99-111: Well-structured schema extension for exit hooks.

The exitHooks array addition is properly implemented with:

  • Appropriate validation for each exit hook object
  • UUID validation for jobAgentId
  • Flexible configuration through z.record(z.any())
  • Optional field that maintains backward compatibility

The schema design aligns well with the existing deployment structure.

packages/db/src/schema/resource-deployment-rule.ts (1)

1-210:

❓ Verification inconclusive

Verify impact of disabling resource deployment rule functionality.

The entire resource deployment rule schema and functionality has been commented out, which could be a breaking change if this code is referenced elsewhere in the codebase.

Please verify that:

  1. No existing code imports or uses these commented schemas
  2. This change aligns with the migration to exit hooks functionality
  3. Any dependent functionality has been properly updated or removed

🏁 Script executed:

#!/bin/bash
# Description: Search for usage of resource deployment rule imports and types

# Search for imports of this module
rg -A 3 "from.*resource-deployment-rule" --type ts

# Search for usage of exported types and schemas
rg -A 3 "ResourceDeploymentRule|resourceDeploymentRule|ResourceDeploymentRelationshipType" --type ts

# Search for any database queries using these tables
rg -A 3 "resource_deployment_relationship_rule|resource_deployment_rule_metadata" --type ts

Length of output: 8698


No references to resource deployment rule found – please confirm intent

We’ve searched for imports of resource-deployment-rule, usages of ResourceDeploymentRule, resourceDeploymentRule, ResourceDeploymentRelationshipType, and the table names; nothing outside this file is referencing them. Commenting out this module will not break any existing code.

Please confirm that:

  • This change is intentional as part of the exit‐hooks migration.
  • Any logic, tests, documentation or CI workflows that depended on resource deployment rules have also been updated or removed.
apps/webservice/src/app/api/v1/deployments/route.ts (3)

14-14: LGTM! Proper import for exit hook utility.

The import is correctly added for the new exit hook functionality.


39-39: Good practice: Extracting exitHooks early.

Extracting the exitHooks from the validated request body early in the function improves readability and reusability.


55-60:

❌ Incorrect review comment

Review transaction handling in upsertExitHook.

The exit hook processing logic is correctly implemented with Promise.all for concurrent execution. However, verify that the upsertExitHook function properly handles nested transactions since it's called within the existing database context.

From the relevant code snippets, I can see that upsertExitHook creates its own transaction with db.transaction(). This could lead to nested transactions which may cause issues depending on the database driver.

Also applies to: 72-75


🏁 Script executed:

#!/bin/bash
# Description: Check how the database driver handles nested transactions

# Search for transaction handling patterns in the codebase
rg -A 5 -B 5 "db\.transaction|tx\.transaction" --type ts

# Look for any existing nested transaction patterns
rg -A 10 "transaction.*transaction" --type ts

Length of output: 44891


upsertExitHook creates independent transactions
In this route handler, ctx.db is the root database client (not already inside a transaction), so each call to upsertExitHook(ctx.db, …) invokes a top-level db.transaction(). There is no nested transaction in this context, and the existing implementation is correct.

Likely an incorrect or invalid review comment.

packages/db/src/schema/event.ts (1)

30-46: LGTM! Well-designed unique constraint for hook data integrity.

The unique index on (name, scopeType, scopeId) properly enforces that hook names must be unique within each scope, which is essential for the exit hooks upsert functionality. This prevents duplicate hooks and ensures data consistency.

packages/db/drizzle/0107_small_deathbird.sql (1)

1-2: LGTM! Migration script correctly implements the required unique indexes.

The SQL statements properly create the unique indexes that correspond to the schema changes in the TypeScript files. The btree indexes are appropriate for enforcing uniqueness constraints on the specified column combinations.

apps/webservice/src/app/api/v1/deployments/[deploymentId]/openapi.ts (1)

129-132: LGTM! OpenAPI schema correctly documents the exit hooks functionality.

The exitHooks property is properly defined as an array referencing the ExitHook schema component. This aligns well with the API implementation and provides clear documentation for consumers of the API.

apps/webservice/src/app/api/v1/deployments/openapi.ts (1)

11-33: LGTM! Well-defined ExitHook schema with proper structure.

The ExitHook schema is well-structured with appropriate types, descriptions, and examples. The required fields make sense for exit hook functionality.

packages/db/src/schema/runbook.ts (2)

3-10: LGTM! Proper import additions for unique index functionality.

The added uniqueIndex import is correctly included to support the new index definition.


20-38: LGTM! Proper database schema refactoring with unique index.

The refactoring from object literal to three-argument pgTable form is the correct approach for adding indexes in Drizzle. The unique index on (name, systemId) ensures runbook name uniqueness within each system, which is a sensible business constraint for the exit hooks functionality.

apps/webservice/src/app/api/v1/deployments/_utils/upsertExitHook.ts (5)

1-11: LGTM! Well-structured imports and type definition.

The imports are appropriate and the ExitHookInsert type clearly defines the expected structure for exit hook data.


13-27: LGTM! Proper hook upsert implementation.

The function correctly handles the unique constraint on (name, scopeType, scopeId) and appropriately updates the action on conflicts.


46-75: LGTM! Well-defined standard variables for exit hooks.

The predefined variables (resourceId and deploymentId) are appropriate for exit hook functionality. The onConflictDoNothing strategy is correct to preserve existing variable configurations.


77-78: LGTM! Simple and correct hook-runbook association.

The function properly handles the relationship between hooks and runbooks with appropriate conflict resolution.


80-90:

❌ Incorrect review comment

Verify transaction nesting behavior.

The function accepts a Tx parameter but then creates a new transaction with db.transaction(). This could cause issues if the Tx is already part of an ongoing transaction.

Please verify how this function is intended to be used. If it should work within existing transactions, consider using the passed db parameter directly. If it needs its own transaction, consider accepting the raw database client instead.


🏁 Script executed:

#!/bin/bash
# Description: Check how upsertExitHook is called to understand transaction context
# Expected: Find usage patterns to determine if nested transactions are intended

rg -A 5 -B 5 "upsertExitHook"

Length of output: 5961


🏁 Script executed:

#!/bin/bash
echo "=== upsertExitHook file content (first 50 lines) ==="
sed -n '1,50p' apps/webservice/src/app/api/v1/deployments/_utils/upsertExitHook.ts || echo "File not found"

echo
echo "=== Searching for Tx alias definitions ==="
rg -n "type Tx" -n .

echo
echo "=== Searching for Kysely instantiation ==="
rg -n "new Kysely" -n .

echo
echo "=== Searching for ctx.db assignment in middleware ==="
rg -n "ctx\\.db" -n apps/webservice/src/app/api/v1

Length of output: 6046


🏁 Script executed:

#!/bin/bash
echo "=== Inspecting middleware.ts ==="
sed -n '1,200p' apps/webservice/src/app/api/v1/middleware.ts || echo "File not found"

echo
echo "=== Inspecting db common.ts (Tx and transaction) ==="
sed -n '1,200p' packages/db/src/common.ts || echo "File not found"

Length of output: 3551


No nested‐transaction issue – upsertExitHook always uses the root db

The upsertExitHook helper is only ever invoked with ctx.db (the top-level client), not a tx from another transaction. Each call correctly starts its own transaction for atomicity, so there’s no accidental nesting in existing code.

Likely an incorrect or invalid review comment.

Comment on lines 121 to 125
const { exitHooks } = body;
if (exitHooks != null)
await Promise.all(
exitHooks.map((eh) => upsertExitHook(db, updatedDeployment, eh)),
);
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 transaction handling and improve error handling.

There are several concerns with the exit hooks processing:

  1. Nested transaction issue: The upsertExitHook function creates its own transaction (as seen in the relevant code snippet), but it's being called with db which is already a transaction context. This could lead to nested transaction issues.

  2. Error handling: If any exit hook processing fails, the deployment update has already been committed to the database, potentially leaving the system in an inconsistent state.

  3. Transaction isolation: Using Promise.all for concurrent processing might not provide proper transaction isolation.

Consider this approach to fix the issues:

-      const { exitHooks } = body;
-      if (exitHooks != null)
-        await Promise.all(
-          exitHooks.map((eh) => upsertExitHook(db, updatedDeployment, eh)),
-        );
+      const { exitHooks, ...deploymentData } = body;
+      
+      const updatedDeployment = await db.transaction(async (tx) => {
+        const deployment = await tx
+          .update(SCHEMA.deployment)
+          .set(deploymentData)
+          .where(eq(SCHEMA.deployment.id, deploymentId))
+          .returning()
+          .then(takeFirst);
+        
+        if (exitHooks != null) {
+          for (const exitHook of exitHooks) {
+            await upsertExitHook(tx, deployment, exitHook);
+          }
+        }
+        
+        return deployment;
+      });

This ensures all operations are within a single transaction and processes exit hooks sequentially to avoid concurrency issues.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In apps/webservice/src/app/api/v1/deployments/[deploymentId]/route.ts around
lines 121 to 125, the current code calls upsertExitHook with a transaction
context that itself starts a transaction, causing nested transactions, and uses
Promise.all which can lead to concurrency and error handling issues. To fix
this, refactor the code so that all exit hook operations run within the same
outer transaction without starting new transactions inside upsertExitHook, and
process the exit hooks sequentially (e.g., with a for loop and await) instead of
concurrently. This ensures proper transaction handling, isolation, and
consistent error management.

Comment on lines 1135 to 1138
},
"exitHooks": {
"type": "array"
}
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

Add items definition for exitHooks in create schema
The exitHooks array in the create deployment request schema lacks an "items" definition, so its element type is unconstrained. This will break validation.

Include a reference to the ExitHook schema, for example:

-"exitHooks": {
-  "type": "array"
-},
+"exitHooks": {
+  "type": "array",
+  "items": {
+    "$ref": "#/components/schemas/ExitHook"
+  },
+  "nullable": true
+},
📝 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
},
"exitHooks": {
"type": "array"
}
},
"exitHooks": {
"type": "array",
"items": {
"$ref": "#/components/schemas/ExitHook"
},
"nullable": true
},
🤖 Prompt for AI Agents
In openapi.v1.json around lines 1135 to 1138, the "exitHooks" array in the
create deployment request schema is missing an "items" definition, causing its
element type to be unconstrained and breaking validation. Fix this by adding an
"items" property that references the "ExitHook" schema to specify the type of
elements allowed in the array.

@adityachoudhari26 adityachoudhari26 merged commit 572b9af into main May 28, 2025
9 of 10 checks passed
@adityachoudhari26 adityachoudhari26 deleted the exithooks-api branch May 28, 2025 23:27
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