Skip to content

fix(notification): prevent out-of-memory when computing digest notifications (#16691)#16735

Open
T0t1n wants to merge 1 commit into
masterfrom
issue/16691
Open

fix(notification): prevent out-of-memory when computing digest notifications (#16691)#16735
T0t1n wants to merge 1 commit into
masterfrom
issue/16691

Conversation

@T0t1n

@T0t1n T0t1n commented Jun 22, 2026

Copy link
Copy Markdown

Proposed changes

  • Read the notification stream range in paginated batches instead of loading the whole range at once. rawFetchRangeNotifications now paginates the XRANGE (exclusive ms-seq cursor + COUNT) and hands each batch to the caller, which filters and transforms it on the fly. Before, the whole range of the digest period was loaded and mapped before being filtered, which caused out-of-memory on large ranges.
  • Keep in memory only the events that belong to the digest's triggers (filtering during the read), not the whole range.
  • Bound the content kept per digest by its cumulative byte size (events vary a lot in size since each carries a full STIX object). The size is taken from the raw Redis fields already read, with no re-serialization. Past the budget the content is truncated, the read stops, and a warning is logged. New setting notification_manager:max_digest_content_size (bytes, default 500 MB).

Related issues

How to test this PR

  • Schedule a Digest notification on a trigger, generate matching events during the period, and check the digest is delivered with the expected content.
  • Unit tests:
    cd opencti-platform/opencti-graphql
    yarn vitest run --config vitest.config.ci-unit.ts \
      tests/01-unit/database/redis-stream-notifications-test.ts \
      tests/01-unit/manager/digest-notification-test.ts
    

Checklist

  • I consider the submitted work as finished
  • I tested the code for its functionality
  • I wrote test cases for the relevant use cases (coverage and e2e)
  • I added/updated the relevant documentation
  • Where necessary, I refactored code to improve the overall quality

Further comments

The range read advances on the full ms-seq stream id with an exclusive cursor, so events sharing the same timestamp across batch boundaries are read exactly once (no duplicate, no skip). Termination and the cursor use the raw XRANGE result (before the live filter), so a batch containing only non-live entries does not stop the iteration. Both are covered by unit tests.

…cations

Read the notification stream range in paginated batches and keep only the events matching the digest, instead of loading the whole range in memory. Bound the retained content by its cumulative byte size, configurable via notification_manager:max_digest_content_size.
Copilot AI review requested due to automatic review settings June 22, 2026 07:27
@codecov

codecov Bot commented Jun 22, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 94.64286% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 24.06%. Comparing base (0cae254) to head (1690b54).
⚠️ Report is 45 commits behind head on master.

Files with missing lines Patch % Lines
...opencti-graphql/src/manager/notificationManager.ts 86.95% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master   #16735      +/-   ##
==========================================
+ Coverage   23.97%   24.06%   +0.09%     
==========================================
  Files        3268     3268              
  Lines      173078   173930     +852     
  Branches    42892    43354     +462     
==========================================
+ Hits        41492    41862     +370     
- Misses     131586   132068     +482     
Flag Coverage Δ
opencti-client-python 46.30% <ø> (ø)
opencti-front 5.63% <ø> (+0.11%) ⬆️
opencti-graphql 66.59% <94.64%> (+0.03%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

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

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@Filigran-Automation Filigran-Automation added the filigran team Item from the Filigran team. label Jun 22, 2026
@Filigran-Automation Filigran-Automation changed the title fix(notification): prevent out-of-memory when computing digest notifications fix(notification): prevent out-of-memory when computing digest notifications (#16691) Jun 22, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR addresses digest-notification OOMs by changing notification-range reads from “load everything then filter” to a paginated, callback-driven scan that filters/accumulates incrementally and enforces a max retained-byte budget per digest.

Changes:

  • Refactors notification-range fetching to be batch/pagination based with an early-stop callback and per-entry stored byte-size metadata.
  • Updates digest computation to retain only matching trigger events while scanning the range, with truncation when a configurable byte cap is reached.
  • Adds unit coverage for pagination semantics (exclusive cursor, no dup/skip across ms-seq boundaries, early-stop) and digest truncation behavior.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
opencti-platform/opencti-graphql/src/manager/notificationManager.ts Adds byte-capped incremental digest content collection and truncation warning.
opencti-platform/opencti-graphql/src/database/redis-stream.ts Implements paginated XRANGE range reads and computes per-entry stored byte size.
opencti-platform/opencti-graphql/src/database/stream/stream-utils.ts Introduces SizedNotifEvent and updates the raw client contract to callback-based range reads.
opencti-platform/opencti-graphql/src/database/stream/stream-handler.ts Adapts fetchRangeNotifications to the new callback-based API.
opencti-platform/opencti-graphql/tests/01-unit/database/redis-stream-notifications-test.ts Adds unit tests for range pagination, cursor semantics, filtering, and early-stop.
opencti-platform/opencti-graphql/tests/01-unit/manager/digest-notification-test.ts Adds unit tests for digest content collection across batches and byte-budget truncation.

callback: (events: Array<SizedNotifEvent<T>>) => Promise<boolean | void> | boolean | void,
): Promise<void> => {
const client = getClientBase();
const endId = `${end.getTime()}`;
Comment on lines +50 to +51
export const DEFAULT_MAX_DIGEST_CONTENT_SIZE = 500 * 1024 * 1024; // 500 MB
const MAX_DIGEST_CONTENT_SIZE = conf.get('notification_manager:max_digest_content_size') || DEFAULT_MAX_DIGEST_CONTENT_SIZE;
Comment on lines +623 to +629
const content: Array<KnowledgeNotificationEvent> = [];
let byteSize = 0;
let truncated = false;
await fetchRangeNotifications<KnowledgeNotificationEvent>(fromDate, toDate, (events) => {
for (let i = 0; i < events.length; i += 1) {
const { event: notification, byteSize: notificationSize } = events[i];
if (triggerIds.includes(notification.notification_id)) {
Comment on lines +44 to +46
afterEach(() => {
vi.clearAllMocks();
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

filigran team Item from the Filigran team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(notification): out-of-memory when computing digest notifications over a large range

3 participants