Skip to content

Conversation

@lindesvard
Copy link
Contributor

@lindesvard lindesvard commented Jan 22, 2026

Summary by CodeRabbit

  • New Features

    • Added interactive tool for assigning products to organizations with checkout link generation and user confirmation.
  • Performance

    • Improved event buffering with local micro-batching to reduce Redis operations.
    • Implemented throttled event publishing to decrease pub/sub load.
  • Refactor

    • Simplified event listener logic.

✏️ Tip: You can customize this high-level summary in your review settings.

@vercel
Copy link

vercel bot commented Jan 22, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Review Updated (UTC)
openpanel-public Error Error Jan 22, 2026 8:45am

Request Review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 22, 2026

📝 Walkthrough

Walkthrough

This PR introduces local micro-batching to the event buffer with controlled Redis flushing, removes redundant Redis keyevent subscription logic from the live controller, and adds a new interactive script for assigning Polar products to organizations. Events are now buffered in memory and flushed in batches rather than written per-event.

Changes

Cohort / File(s) Summary
Event buffer refactoring
packages/db/src/buffers/event-buffer.ts, packages/db/src/buffers/event-buffer.test.ts
Introduces local micro-batching with explicit flush() calls. Events accumulate in memory with flushing at 10ms intervals or max batch size; replaced direct per-event Redis writes with batched multi/pipeline operations. Added PendingEvent type, public flush() method, and throttled pub/sub signaling. Simplified active visitor tracking to ZADD-based approach. Test cases updated to call flush() explicitly, affecting timing and buffer assertions.
Live event controller simplification
apps/api/src/controllers/live.controller.ts
Removed exported getLiveEventInfo() function and Redis keyevent expiration subscription logic (psubscribeToPublishedEvent). Event listening now handles only 'events' channel with 'saved' type, reducing complexity.
Polar product assignment script
packages/payments/scripts/assign-product-to-org.ts
New interactive TypeScript script for assigning existing Polar products to organizations. Guides user through product/organization selection with autocomplete, displays review summary, and generates Stripe checkout links with metadata upon confirmation.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • #262: Modifies event-buffer and session-buffer logic with overlapping micro-batching and flush() functionality changes to the same core buffering systems.

Poem

🐰✨ A hop, batch, and flush we go,
Events gather, then let flow,
Micro-batches keep us swift,
Products assigned, each a gift!
Redis smiles at fewer calls—
Efficiency hops through these halls! 🎉

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Feature/optimize event buffer' directly relates to the main changes in the pull request, which involve introducing local micro-batching and optimization of the EventBuffer class to reduce Redis round-trips and improve performance.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

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

🤖 Fix all issues with AI agents
In `@packages/db/src/buffers/event-buffer.ts`:
- Around line 395-402: The catch block in the flushLocalBufferToRedis flow
currently logs the failure but drops events from eventsToFlush (causing data
loss); modify the catch handler in the method that builds and executes the Redis
multi (look for eventsToFlush and this.pendingEvents) to re-queue the failed
events back onto this.pendingEvents (preserving order—e.g., unshift or concat
depending on how pendingEvents is consumed), ensure you do this before
clearing/resetting isFlushing, and avoid duplicating events if a partial success
path exists (check any success branch that removes events). Also consider
incrementing a retry counter or emitting a metric/log entry when re-queuing so
persistent failures are observable.

In `@packages/payments/scripts/assign-product-to-org.ts`:
- Around line 42-50: The prompt object for the Polar API key uses the wrong
Inquirer type string ('string'); update the prompt definition for polarApiKey so
its type property is 'input' (i.e., change type: 'string' to type: 'input')
while keeping the existing name 'polarApiKey' and validate function intact to
ensure the same validation behavior.
🧹 Nitpick comments (3)
packages/payments/scripts/assign-product-to-org.ts (1)

130-133: Avoid duplicate Polar client instantiation.

A Polar client is already created at line 54-57 inside promptForInput() but is not returned. Instead of creating it again here, consider returning the client from promptForInput() or moving client creation to main() only.

Option: Return polar client from promptForInput
-  return {
-    ...polarCredentials,
-    ...restOfAnswers,
-  };
+  return {
+    ...polarCredentials,
+    ...restOfAnswers,
+    polar, // Return the already-created client
+  };
}

async function main() {
  console.log('Assigning existing product to organization...');
  const input = await promptForInput();

-  const polar = new Polar({
-    accessToken: input.polarApiKey,
-    server: input.isProduction ? 'production' : 'sandbox',
-  });
+  const polar = input.polar;
packages/db/src/buffers/event-buffer.ts (1)

60-71: Consider cleaning up timers on shutdown.

The flushTimer and publishTimer are not cleaned up if the EventBuffer is destroyed or the process shuts down gracefully. This could lead to timer leaks or callbacks firing after cleanup.

Consider adding a cleanup/destroy method
public destroy() {
  if (this.flushTimer) {
    clearTimeout(this.flushTimer);
    this.flushTimer = null;
  }
  if (this.publishTimer) {
    clearTimeout(this.publishTimer);
    this.publishTimer = null;
  }
}
packages/db/src/buffers/event-buffer.test.ts (1)

83-157: Consider verifying calculated duration in the test.

The test validates that events move to the buffer correctly but doesn't verify that the duration is actually calculated. Consider adding a check that processes the buffer and verifies the duration field is set correctly (e.g., ~1000ms between view1 and view2).

Comment on lines 395 to +402
} catch (error) {
this.logger.error('Failed to add event to Redis buffer', { error });
this.logger.error('Failed to flush local buffer to Redis', {
error,
eventCount: eventsToFlush.length,
});
} finally {
this.isFlushing = 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 | 🟠 Major

Events may be lost on Redis flush failure.

If multi.exec() fails, the events in eventsToFlush are discarded without retry. For critical event tracking, consider re-queuing failed events back to pendingEvents in the catch block.

Proposed fix to re-queue failed events
    } catch (error) {
      this.logger.error('Failed to flush local buffer to Redis', {
        error,
        eventCount: eventsToFlush.length,
      });
+     // Re-queue failed events for retry
+     this.pendingEvents = [...eventsToFlush, ...this.pendingEvents];
    } finally {
      this.isFlushing = false;
    }
📝 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
} catch (error) {
this.logger.error('Failed to add event to Redis buffer', { error });
this.logger.error('Failed to flush local buffer to Redis', {
error,
eventCount: eventsToFlush.length,
});
} finally {
this.isFlushing = false;
}
} catch (error) {
this.logger.error('Failed to flush local buffer to Redis', {
error,
eventCount: eventsToFlush.length,
});
// Re-queue failed events for retry
this.pendingEvents = [...eventsToFlush, ...this.pendingEvents];
} finally {
this.isFlushing = false;
}
🤖 Prompt for AI Agents
In `@packages/db/src/buffers/event-buffer.ts` around lines 395 - 402, The catch
block in the flushLocalBufferToRedis flow currently logs the failure but drops
events from eventsToFlush (causing data loss); modify the catch handler in the
method that builds and executes the Redis multi (look for eventsToFlush and
this.pendingEvents) to re-queue the failed events back onto this.pendingEvents
(preserving order—e.g., unshift or concat depending on how pendingEvents is
consumed), ensure you do this before clearing/resetting isFlushing, and avoid
duplicating events if a partial success path exists (check any success branch
that removes events). Also consider incrementing a retry counter or emitting a
metric/log entry when re-queuing so persistent failures are observable.

Comment on lines +42 to +50
{
type: 'string',
name: 'polarApiKey',
message: 'Enter your Polar API key:',
validate: (input: string) => {
if (!input) return 'API key is required';
return true;
},
},
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 | 🟡 Minor

Use 'input' instead of 'string' for inquirer prompt type.

Inquirer's prompt type should be 'input' for text input fields, not 'string'.

Proposed fix
    {
-     type: 'string',
+     type: 'input',
      name: 'polarApiKey',
      message: 'Enter your Polar API key:',
      validate: (input: string) => {
        if (!input) return 'API key is required';
        return 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
{
type: 'string',
name: 'polarApiKey',
message: 'Enter your Polar API key:',
validate: (input: string) => {
if (!input) return 'API key is required';
return true;
},
},
{
type: 'input',
name: 'polarApiKey',
message: 'Enter your Polar API key:',
validate: (input: string) => {
if (!input) return 'API key is required';
return true;
},
},
🤖 Prompt for AI Agents
In `@packages/payments/scripts/assign-product-to-org.ts` around lines 42 - 50, The
prompt object for the Polar API key uses the wrong Inquirer type string
('string'); update the prompt definition for polarApiKey so its type property is
'input' (i.e., change type: 'string' to type: 'input') while keeping the
existing name 'polarApiKey' and validate function intact to ensure the same
validation behavior.

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