-
Notifications
You must be signed in to change notification settings - Fork 2
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
init #202
init #202
Conversation
WalkthroughThis pull request introduces several changes across multiple files, primarily focusing on the integration of a new dependency, Changes
Possibly related PRs
Suggested reviewers
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? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
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)
Other keywords and placeholders
Documentation and Community
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
🧹 Outside diff range and nitpick comments (11)
packages/events/src/index.ts (1)
7-10
: Consider adding observability and extensibility.As this appears to be an initial implementation, consider these architectural improvements:
- Add structured logging for event handling (success/failure)
- Consider implementing a more scalable event handling pattern (e.g., strategy pattern) for future event types
- Add metrics/monitoring for event processing
Would you like me to provide example implementations for any of these suggestions?
packages/validators/src/events/index.ts (1)
Line range hint
1-24
: Consider adding JSDoc comments for event types.The file structure is well-organized, but adding documentation for the event types and channels would improve maintainability. Consider documenting:
- Purpose and usage of each event type
- Expected payload structure and constraints
- Channel enum values and their use cases
Example documentation:
/** * Channels used for different types of events in the system. */ export enum Channel { /** Events related to job synchronization */ JobSync = "job-sync", // ... (document other channels) } /** * Event schema for target scanning operations. * @property targetProviderId - Unique identifier for the target provider */ export const targetScanEvent = z.object({ targetProviderId: z.string() });packages/db/src/schema/index.ts (1)
Line range hint
9-9
: Remove duplicate export of runbook.jsThe file contains two identical export statements for runbook.js. This redundancy should be eliminated.
Apply this diff to remove the duplicate:
export * from "./runbook.js"; export * from "./team.js"; export * from "./job.js"; export * from "./workspace.js"; export * from "./github.js"; export * from "./deployment-variables.js"; export * from "./dashboard.js"; export * from "./variable-sets.js"; export * from "./invite.js"; export * from "./target-group.js"; export * from "./runbook-variables.js"; export * from "./rbac.js"; -export * from "./runbook.js"; export * from "./job-agent.js";
Also applies to: 20-20
packages/db/src/schema/hook.ts (2)
5-12
: Consider adding indexes for performance optimization.The
runhook
table might benefit from additional indexes:
- A composite index on (scope_type, scope_id) for efficient lookups
- An index on runbook_id for efficient joins
Here's how you could add them:
export const runhook = pgTable("runhook", { id: uuid("id").primaryKey().defaultRandom(), scopeType: text("scope_type").notNull(), scopeId: uuid("scope_id").notNull(), runbookId: uuid("runbook_id") .references(() => runbook.id, { onDelete: "cascade" }) .notNull(), -}); +}, (table) => ({ + scopeIdx: index("runhook_scope_idx").on(table.scopeType, table.scopeId), + runbookIdx: index("runhook_runbook_idx").on(table.runbookId), +}));
5-12
: Document the valid values for scope_type.Please add documentation comments explaining:
- What
scope_type
represents- The valid values it can contain
- Any business rules associated with it
Add documentation like this:
+/** + * Represents a runhook configuration that links a scope (identified by type and ID) + * to a runbook. + * + * @property scopeType - The type of scope this hook applies to. + * Valid values: [list valid values here] + * @property scopeId - The unique identifier of the scope + * @property runbookId - Reference to the runbook to be executed + */ export const runhook = pgTable("runhook", {packages/validators/src/events/hook-events/environment.ts (2)
3-8
: Consider enhancing the base schema with stricter validation.While the current schema is functional, consider adding:
- ISO datetime format validation for
createdAt
- Additional common fields that might be useful across all environment events (e.g.,
version
,source
)const environmentBaseEvent = z.object({ - createdAt: z.string().datetime(), + createdAt: z.string().datetime().regex(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?Z$/), + version: z.string(), + source: z.string(), payload: z.object({ environmentId: z.string().uuid(), }), });
10-13
: Add JSDoc documentation for the event enum.Consider adding documentation to improve code maintainability and clarity.
+/** + * Represents the types of environment-related events that can occur in the system. + * @enum {string} + */ export enum EnvironmentEvent { + /** Emitted when an environment is deleted from the system */ Deleted = "environment.deleted", + /** Emitted when a new environment is created in the system */ Created = "environment.created", }packages/validators/src/events/hook-events/index.ts (2)
15-19
: Consider enhancing error handling in the Zod union schema.While the implementation is correct, adding a custom error message would improve debugging and error reporting.
export const HookEvent = z.union([ environmentDeletedEvent, environmentCreatedEvent, -]); +], { + errorMap: (issue, ctx) => ({ + message: `Invalid hook event type. Expected 'environment.deleted' or 'environment.created', got '${ctx.data?.type}'`, + }), +});
21-27
: Add JSDoc comments to improve documentation.The type guards are well-implemented, but adding JSDoc comments would improve code documentation and IDE support.
-// typeguards +/** + * Type guard to check if an event is an EnvironmentDeletedEvent + * @param event - The hook event to check + * @returns True if the event is an EnvironmentDeletedEvent + */ export const isEnvironmentDeletedEvent = ( event: HookEvent, ): event is EnvironmentDeletedEvent => event.type === EnvironmentEvent.Deleted; + +/** + * Type guard to check if an event is an EnvironmentCreatedEvent + * @param event - The hook event to check + * @returns True if the event is an EnvironmentCreatedEvent + */ export const isEnvironmentCreatedEvent = ( event: HookEvent, ): event is EnvironmentCreatedEvent => event.type === EnvironmentEvent.Created;apps/jobs/src/expired-env-checker/index.ts (1)
Line range hint
21-24
: Add logging for deletion resultsConsider adding logging to track the number of environments deleted and capture any deletion failures. This will help with monitoring and debugging.
Here's a suggested improvement:
- await db - .delete(SCHEMA.environment) - .where(inArray(SCHEMA.environment.id, envIds)); + try { + const result = await db + .delete(SCHEMA.environment) + .where(inArray(SCHEMA.environment.id, envIds)); + console.log(`Successfully deleted ${envIds.length} expired environments`); + } catch (error) { + console.error('Failed to delete expired environments:', error); + throw error; + }packages/events/src/environments/environment-delete.ts (1)
94-107
: Add Error Handling for Promise OperationsCurrently, the promises returned by
dispatchRunbook
are executed withPromise.all
, but any rejection in these promises could lead to unhandled promise rejections.Consider adding error handling to manage any potential rejections from
dispatchRunbook
. This will improve the robustness of your function.Apply this diff to handle potential errors:
await Promise.all(handleLifecycleHooksForTargets); + // Optionally handle errors + await Promise.all(handleLifecycleHooksForTargets).catch((error) => { + // Handle the error appropriately + console.error("Error dispatching runbooks:", error); + // You might want to perform additional error handling or logging here + });
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
⛔ Files ignored due to path filters (1)
pnpm-lock.yaml
is excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (12)
apps/jobs/package.json
(1 hunks)apps/jobs/src/expired-env-checker/index.ts
(1 hunks)packages/db/src/schema/hook.ts
(1 hunks)packages/db/src/schema/index.ts
(1 hunks)packages/events/eslint.config.js
(1 hunks)packages/events/package.json
(1 hunks)packages/events/src/environments/environment-delete.ts
(1 hunks)packages/events/src/index.ts
(1 hunks)packages/events/tsconfig.json
(1 hunks)packages/validators/src/events/hook-events/environment.ts
(1 hunks)packages/validators/src/events/hook-events/index.ts
(1 hunks)packages/validators/src/events/index.ts
(1 hunks)
✅ Files skipped from review due to trivial changes (3)
- packages/events/eslint.config.js
- packages/events/package.json
- packages/events/tsconfig.json
🔇 Additional comments (17)
packages/events/src/index.ts (1)
1-5
: LGTM! Clean import organization.
The imports are well-structured with clear separation between external and local imports.
packages/validators/src/events/index.ts (1)
3-3
: Verify the hook-events module structure.
The export statement follows the barrel pattern correctly. Let's verify the referenced module structure.
✅ Verification successful
Let me generate another script to verify the specific file structure since the previous commands had issues:
Export statement is correctly implemented and follows the project's conventions
The verification confirms that:
- The hook-events module exists and has proper structure
- The index.ts file correctly re-exports from environment.js
- No circular dependencies are present
- The .js extension in imports follows the project's ESM conventions
- The module provides proper type definitions and type guards
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Verify the hook-events module structure and potential issues
# Test 1: Check if the referenced file exists
echo "Checking for hook-events/index.ts or hook-events/index.js..."
fd --type f "index\.(ts|js)$" --parent-dir "hook-events"
# Test 2: Check for potential circular dependencies
echo "Checking for potential circular dependencies..."
rg -l "from.*events" "hook-events/"
# Test 3: Verify consistent import path conventions across the codebase
echo "Verifying import path conventions..."
rg "from.*\.js[\"']" --type ts
Length of output: 27709
Script:
#!/bin/bash
# Description: Verify the hook-events module structure and potential issues
# Test 1: Check if the referenced file exists
echo "Checking for hook-events module files..."
fd "hook-events" packages/validators/src/events/
# Test 2: Check for potential circular dependencies
echo "Checking for potential circular dependencies..."
rg -l "from.*events" packages/validators/src/events/hook-events/
# Test 3: Check the content of hook-events/index.ts
echo "Checking hook-events/index.ts content..."
cat packages/validators/src/events/hook-events/index.ts
Length of output: 1216
packages/db/src/schema/index.ts (1)
22-22
: LGTM!
The new export follows the established pattern and integrates well with the existing schema exports.
packages/db/src/schema/hook.ts (1)
1-4
: LGTM! Imports are well-structured.
The imports are specific and properly scoped, following ESM best practices.
packages/validators/src/events/hook-events/environment.ts (1)
1-23
: Verify event schema usage across the codebase.
Let's ensure these schemas are properly utilized in event handlers and consumers.
✅ Verification successful
Event schemas are properly integrated across the codebase
The verification shows proper integration of the environment event schemas:
- Type guards (
isEnvironmentDeletedEvent
,isEnvironmentCreatedEvent
) are correctly implemented and used - Event handler for deleted environments exists and uses proper typing
- Event emission is properly typed in the expired environment checker
- All imports and type references are consistent
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Check usage of environment events across the codebase
# Check for event handler implementations
echo "Checking event handler implementations..."
rg -t typescript "handleEnvironment(Created|Deleted)" -A 5
# Check for event emission points
echo "Checking event emission points..."
rg -t typescript "emit.*environment\.(created|deleted)" -A 5
# Check for proper type imports
echo "Checking type imports..."
rg -t typescript "import.*Environment(Created|Deleted)Event" -A 2
Length of output: 525
Script:
#!/bin/bash
# Description: Check usage of environment events across the codebase without typescript flag
# Check for event handler implementations
echo "Checking event handler implementations..."
rg "handleEnvironment(Created|Deleted)" -A 5
# Check for event emission points
echo "Checking event emission points..."
rg "emit.*environment\.(created|deleted)" -A 5
# Check for imports and usages
echo "Checking imports and usages..."
rg "Environment(Created|Deleted)Event" -A 2
# Check for enum usage
echo "Checking enum usage..."
rg "EnvironmentEvent\.(Created|Deleted)" -A 2
Length of output: 5129
packages/validators/src/events/hook-events/index.ts (2)
1-13
: LGTM! Well-organized imports and exports.
The imports are properly structured, separating type imports from value imports, and the re-export pattern promotes good module organization.
3-11
: Verify the environment.js imports and type usage.
Let's ensure the imported types and constants are properly defined and used consistently.
✅ Verification successful
All environment event types and imports are correctly defined and used
The verification shows that:
- The
environment.ts
file exists atpackages/validators/src/events/hook-events/environment.ts
and properly exports all the referenced types and constants - The types are consistently used across the codebase:
EnvironmentEvent
enum is used in event handling and job processingEnvironmentCreatedEvent
andEnvironmentDeletedEvent
types are properly imported and used in type checksHookEvent
is correctly used as the main event type in the event handling system
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Verify environment.js exists and check its exports
fd -e js -e ts "environment\.js$" --exec cat {} \;
# Check usage of these types across the codebase
rg -t typescript "EnvironmentEvent\.(Created|Deleted)"
# Verify consistent usage of HookEvent type
rg -t typescript "HookEvent"
Length of output: 211
Script:
#!/bin/bash
# Search for environment.js/ts file
fd "environment\.(js|ts)$"
# If file exists, check its contents
fd "environment\.(js|ts)$" --exec cat {} \;
# Search for type usage without file type flag
rg "EnvironmentCreatedEvent|EnvironmentDeletedEvent|EnvironmentEvent"
# Search for hook events
rg "HookEvent"
Length of output: 23525
apps/jobs/src/expired-env-checker/index.ts (2)
1-5
: LGTM! Clean import organization
The new imports for event handling capabilities are properly organized and align well with the module's new event-driven approach.
8-11
: Verify handling of associated deployment records
The query has been simplified by removing the deployment schema join. While this makes the code cleaner, we should verify that this doesn't leave orphaned deployment records.
Let's check if there's any cleanup logic for associated deployments:
✅ Verification successful
No issues with removing the deployment join
The simplified query in the expired environment checker is correct. When an environment is deleted:
- The system emits an
environment.deleted
event - The event handler (
handleEnvironmentDeleted
) properly manages any associated deployments and targets - The deletion of the environment record triggers cleanup through event handlers rather than through the query itself
The original review concern about orphaned deployment records is not an issue as the system handles this through its event-driven architecture.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Search for deployment cleanup logic related to environment deletion
rg -l 'deployment.*delete.*environment' --type ts
# Check for foreign key constraints that might handle this automatically
rg -l 'foreignKey.*environment.*deployment' --type ts
Length of output: 107
Script:
#!/bin/bash
# Let's check the schema definition to understand the relationship between environment and deployment
ast-grep --pattern 'export const SCHEMA = {
$$$
}'
# Also search for any cascade delete operations or cleanup logic
rg -B 5 -A 5 'environment.*delete|delete.*environment' --type ts
# Check for any database migration files that might define the relationships
fd -e sql -e ts migration
Length of output: 17053
Script:
#!/bin/bash
# Let's check for any foreign key constraints or cascade delete operations in the schema
ast-grep --pattern 'createTable($_, $_)'
# Let's also check for any environment deletion event handlers
ast-grep --pattern 'handleEnvironmentDeleted($$$)'
# And check for any deployment cleanup in the expired env checker
rg -B 5 -A 5 'expiredEnvironments' --type ts
Length of output: 2009
Script:
#!/bin/bash
# Let's examine the environment deletion event handler implementation
rg -B 10 -A 10 'handleEnvironmentDeleted' --type ts
# And check the environment event handler in the events package
cat packages/events/src/environments/environment-delete.ts
Length of output: 4939
apps/jobs/package.json (2)
17-17
: LGTM! Dependency addition looks correct.
The new @ctrlplane/events
workspace dependency is properly added and follows the project's dependency management conventions.
17-17
: Verify the workspace package configuration.
Let's ensure the new @ctrlplane/events
package is properly configured in the workspace.
✅ Verification successful
Workspace package configuration is properly set up
The verification confirms that:
- Package directory exists at
packages/events
- Package.json is correctly configured with:
- Proper name
@ctrlplane/events
- Required workspace dependencies
- Valid exports configuration
- Essential build scripts
- Proper name
- Required source files are present:
src/index.ts
src/environments/environment-delete.ts
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Verify the existence and basic configuration of @ctrlplane/events package
# Test 1: Check if the package directory exists
echo "Checking package directory..."
fd -t d "events$" packages/
# Test 2: Verify package.json exists and has correct configuration
echo "Checking package.json configuration..."
fd -t f "package.json" packages/events -x cat {} \; 2>/dev/null
# Test 3: Check for essential files mentioned in the summary
echo "Checking for essential files..."
fd -t f "environment-delete.ts|index.ts" packages/events/src 2>/dev/null
Length of output: 1565
packages/events/src/environments/environment-delete.ts (6)
35-38
: Confirm Logical Conditions in 'checks' are Accurate
The construction of the checks
condition using and
is logically sound. It correctly ensures that:
- The
targetFilter
is notnull
. - The environment ID is not equal to the deleted environment's ID.
39-44
: Verify Handling of Empty 'system.environments' Array
After fetching the system
, you access system.environments
. If system.environments
is an empty array, subsequent operations like mapping over envFilters
might not behave as expected.
Please verify that system.environments
will always contain at least one environment or adjust the code to handle the case where system.environments
is empty to prevent potential errors downstream.
45-47
: Ensure 'envFilters' Correctly Reflects Active Environments
The mapping and filtering of system.environments
to create envFilters
is appropriate. It collects all present targetFilter
values from the environments.
56-71
: Confirm Logic for 'removedFromSystemTargets' Selection
Using a conditional to determine removedFromSystemTargets
based on envFilters.length
is logical. If there are other environment filters, you compute the targets removed from the system; otherwise, you assume all targets are removed.
110-111
: Export Statement Provides Clear Public Interface
Exporting handleEnvironmentDeleted
as the public interface to handleTargets
is appropriate. It keeps the internal implementation encapsulated and provides a clean API for handling the EnvironmentDeletedEvent
.
73-92
:
Handle Empty 'system.deployments' When Building 'or' Condition
If system.deployments
is an empty array, the spread operator in the or
condition will result in no arguments being passed to or()
. Depending on the implementation of the or()
function from @ctrlplane/db
, this might cause an error or unintended behavior.
Consider adding a check for system.deployments.length
before constructing the or
condition to handle cases where there are no deployments.
Apply this diff to handle the empty case:
+ if (system.deployments.length === 0) return;
const runhooks = await db
.select()
.from(SCHEMA.runhook)
.innerJoin(
SCHEMA.runhookEvent,
eq(SCHEMA.runhookEvent.runhookId, SCHEMA.runhook.id),
)
.where(
or(
...system.deployments.map((deployment) =>
and(
eq(SCHEMA.runhook.scopeType, "deployment"),
eq(SCHEMA.runhook.scopeId, deployment.id),
eq(SCHEMA.runhookEvent.eventType, "environment.deleted"),
),
),
),
)
.then((r) => r.map((rh) => rh.runhook));
Alternatively, ensure that the or()
function gracefully handles an empty array of conditions without throwing an error.
packages/events/src/index.ts
Outdated
export const handleHookEvent = (event: HookEvent): Promise<void> => { | ||
if (isEnvironmentDeletedEvent(event)) handleEnvironmentDeleted(event); | ||
throw new Error(`Unknown event type: ${event.type}`); | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix critical issues in event handling logic.
The current implementation has several issues:
- The throw statement will execute regardless of the event type
- The Promise from handleEnvironmentDeleted is not awaited
- No return statement after handling the event
- Missing error handling for handleEnvironmentDeleted
Apply this fix:
-export const handleHookEvent = (event: HookEvent): Promise<void> => {
- if (isEnvironmentDeletedEvent(event)) handleEnvironmentDeleted(event);
- throw new Error(`Unknown event type: ${event.type}`);
-};
+export const handleHookEvent = async (event: HookEvent): Promise<void> => {
+ try {
+ if (isEnvironmentDeletedEvent(event)) {
+ await handleEnvironmentDeleted(event);
+ return;
+ }
+ throw new Error(`Unknown event type: ${event.type}`);
+ } catch (error) {
+ throw new Error(`Failed to handle event: ${error.message}`);
+ }
+};
📝 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.
export const handleHookEvent = (event: HookEvent): Promise<void> => { | |
if (isEnvironmentDeletedEvent(event)) handleEnvironmentDeleted(event); | |
throw new Error(`Unknown event type: ${event.type}`); | |
}; | |
export const handleHookEvent = async (event: HookEvent): Promise<void> => { | |
try { | |
if (isEnvironmentDeletedEvent(event)) { | |
await handleEnvironmentDeleted(event); | |
return; | |
} | |
throw new Error(`Unknown event type: ${event.type}`); | |
} catch (error) { | |
throw new Error(`Failed to handle event: ${error.message}`); | |
} | |
}; |
export const runhookEvent = pgTable("runhook_event", { | ||
id: uuid("id").primaryKey().defaultRandom(), | ||
runhookId: uuid("runhook_id") | ||
.references(() => runhook.id, { onDelete: "cascade" }) | ||
.notNull(), | ||
eventType: text("event_type").notNull(), | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Consider adding essential fields for event tracking.
The runhook_event
table appears to be missing some common fields typically needed for event tracking:
- Timestamp fields (created_at, processed_at)
- Event payload or metadata field
- Event status field
- Index on runhookId for efficient lookups
Consider enhancing the schema like this:
export const runhookEvent = pgTable("runhook_event", {
id: uuid("id").primaryKey().defaultRandom(),
runhookId: uuid("runhook_id")
.references(() => runhook.id, { onDelete: "cascade" })
.notNull(),
eventType: text("event_type").notNull(),
+ payload: jsonb("payload"),
+ status: text("status").notNull().default("pending"),
+ createdAt: timestamp("created_at").notNull().defaultNow(),
+ processedAt: timestamp("processed_at"),
+ error: text("error"),
-});
+}, (table) => ({
+ runhookIdx: index("runhook_event_runhook_idx").on(table.runhookId),
+ createdAtIdx: index("runhook_event_created_at_idx").on(table.createdAt),
+}));
Also, consider adding documentation for valid event types:
+/**
+ * Represents events associated with runhooks.
+ *
+ * @property eventType - The type of event.
+ * Valid values: [list valid values here]
+ * @property payload - Additional event data in JSON format
+ * @property status - Event processing status (pending, processing, completed, failed)
+ */
export const runhookEvent = pgTable("runhook_event", {
📝 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.
export const runhookEvent = pgTable("runhook_event", { | |
id: uuid("id").primaryKey().defaultRandom(), | |
runhookId: uuid("runhook_id") | |
.references(() => runhook.id, { onDelete: "cascade" }) | |
.notNull(), | |
eventType: text("event_type").notNull(), | |
}); | |
/** | |
* Represents events associated with runhooks. | |
* | |
* @property eventType - The type of event. | |
* Valid values: [list valid values here] | |
* @property payload - Additional event data in JSON format | |
* @property status - Event processing status (pending, processing, completed, failed) | |
*/ | |
export const runhookEvent = pgTable("runhook_event", { | |
id: uuid("id").primaryKey().defaultRandom(), | |
runhookId: uuid("runhook_id") | |
.references(() => runhook.id, { onDelete: "cascade" }) | |
.notNull(), | |
eventType: text("event_type").notNull(), | |
payload: jsonb("payload"), | |
status: text("status").notNull().default("pending"), | |
createdAt: timestamp("created_at").notNull().defaultNow(), | |
processedAt: timestamp("processed_at"), | |
error: text("error"), | |
}, (table) => ({ | |
runhookIdx: index("runhook_event_runhook_idx").on(table.runhookId), | |
createdAtIdx: index("runhook_event_created_at_idx").on(table.createdAt), | |
})); |
export const environmentDeletedEvent = environmentBaseEvent.extend({ | ||
type: z.literal(EnvironmentEvent.Deleted), | ||
}); | ||
export type EnvironmentDeletedEvent = z.infer<typeof environmentDeletedEvent>; | ||
|
||
export const environmentCreatedEvent = environmentBaseEvent.extend({ | ||
type: z.literal(EnvironmentEvent.Created), | ||
}); | ||
export type EnvironmentCreatedEvent = z.infer<typeof environmentCreatedEvent>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Consider extending event payloads with event-specific data.
The current implementation uses the same payload structure for both events. Consider adding event-specific fields to capture relevant data:
export const environmentDeletedEvent = environmentBaseEvent.extend({
type: z.literal(EnvironmentEvent.Deleted),
+ payload: z.object({
+ environmentId: z.string().uuid(),
+ deletedBy: z.string().uuid(),
+ reason: z.string().optional(),
+ }),
});
export const environmentCreatedEvent = environmentBaseEvent.extend({
type: z.literal(EnvironmentEvent.Created),
+ payload: z.object({
+ environmentId: z.string().uuid(),
+ createdBy: z.string().uuid(),
+ configuration: z.record(z.unknown()),
+ }),
});
Committable suggestion skipped: line range outside the PR's diff.
const events = expiredEnvironments.map((env) => ({ | ||
type: EnvironmentEvent.Deleted, | ||
createdAt: new Date().toISOString(), | ||
payload: { environmentId: env.id }, | ||
})); | ||
await Promise.all(events.map(handleHookEvent)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Consider adding error handling for event processing
While concurrent event processing is efficient, a failure in handleHookEvent
for one environment could cause others to fail silently. Consider adding error handling and possibly a transaction to ensure atomicity.
Here's a suggested improvement:
- await Promise.all(events.map(handleHookEvent));
+ try {
+ await Promise.all(
+ events.map(async (event) => {
+ try {
+ await handleHookEvent(event);
+ } catch (error) {
+ console.error(`Failed to process event for environment ${event.payload.environmentId}:`, error);
+ throw error; // Re-throw to trigger the outer catch
+ }
+ })
+ );
+ } catch (error) {
+ console.error('Failed to process some environment deletion events:', error);
+ throw error; // Prevent environment deletion if event processing fails
+ }
📝 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.
const events = expiredEnvironments.map((env) => ({ | |
type: EnvironmentEvent.Deleted, | |
createdAt: new Date().toISOString(), | |
payload: { environmentId: env.id }, | |
})); | |
await Promise.all(events.map(handleHookEvent)); | |
const events = expiredEnvironments.map((env) => ({ | |
type: EnvironmentEvent.Deleted, | |
createdAt: new Date().toISOString(), | |
payload: { environmentId: env.id }, | |
})); | |
try { | |
await Promise.all( | |
events.map(async (event) => { | |
try { | |
await handleHookEvent(event); | |
} catch (error) { | |
console.error(`Failed to process event for environment ${event.payload.environmentId}:`, error); | |
throw error; // Re-throw to trigger the outer catch | |
} | |
}) | |
); | |
} catch (error) { | |
console.error('Failed to process some environment deletion events:', error); | |
throw error; // Prevent environment deletion if event processing fails | |
} |
const handleTargets = async (event: EnvironmentDeletedEvent) => { | ||
const environment = await db | ||
.select() | ||
.from(SCHEMA.environment) | ||
.where(eq(SCHEMA.environment.id, event.payload.environmentId)) | ||
.then(takeFirstOrNull); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add Null Check for 'environment' Before Accessing Its Properties
While you check if environment?.targetFilter == null
, there is a possibility that environment
itself could be null
if the database query does not find a matching record. Accessing environment.id
later without confirming that environment
is not null
may lead to runtime errors.
Consider adding a null check for environment
after retrieving it from the database to ensure it exists before accessing its properties.
Apply this diff to add the null check:
const environment = await db
.select()
.from(SCHEMA.environment)
.where(eq(SCHEMA.environment.id, event.payload.environmentId))
.then(takeFirstOrNull);
+ if (environment == null) return;
if (environment.targetFilter == null) return;
📝 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.
const handleTargets = async (event: EnvironmentDeletedEvent) => { | |
const environment = await db | |
.select() | |
.from(SCHEMA.environment) | |
.where(eq(SCHEMA.environment.id, event.payload.environmentId)) | |
.then(takeFirstOrNull); | |
const handleTargets = async (event: EnvironmentDeletedEvent) => { | |
const environment = await db | |
.select() | |
.from(SCHEMA.environment) | |
.where(eq(SCHEMA.environment.id, event.payload.environmentId)) | |
.then(takeFirstOrNull); | |
if (environment == null) return; | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Outside diff range and nitpick comments (1)
apps/jobs/Dockerfile (1)
Node.js version 22 conflicts with package.json requirements
The package.json explicitly requires Node.js version
>=20.12.0
, but the Dockerfile is using Node 22 which is not yet an LTS release. This could lead to compatibility issues. Using Node.js 20 LTS would better align with the project's requirements while ensuring stability.🔗 Analysis chain
Line range hint
1-1
: Consider using a more stable Node.js versionThe Dockerfile uses Node 22 which is very recent and might introduce stability issues in production. Consider using LTS version 20 instead.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Check if package.json specifies a different Node.js version requirement rg -A 5 '"node":' package.jsonLength of output: 213
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
📒 Files selected for processing (2)
apps/jobs/Dockerfile
(1 hunks)packages/events/tsconfig.json
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/events/tsconfig.json
🔇 Additional comments (1)
apps/jobs/Dockerfile (1)
30-30
: LGTM: Package addition follows established pattern
The addition of packages/events/package.json
is correctly placed with other package.json copies and follows the established pattern for dependency management in the multi-package setup.
Summary by CodeRabbit
New Features
Bug Fixes
Documentation
Chores