Skip to content

fix: added more cleanup for event service#5341

Merged
akhilmhdh merged 1 commit intomainfrom
feat/memory-leak-patch
Feb 2, 2026
Merged

fix: added more cleanup for event service#5341
akhilmhdh merged 1 commit intomainfrom
feat/memory-leak-patch

Conversation

@akhilmhdh
Copy link
Member

Context

This PR tries to fix the memory leak happening in the event subscription service. This does the cleanups missing and de-referencing variables.

Screenshots

Steps to verify the change

Type

  • Fix
  • Feature
  • Improvement
  • Breaking
  • Docs
  • Chore

Checklist

  • Title follows the conventional commit format: type(scope): short description (scope is optional, e.g., fix: prevent crash on sync or fix(api): handle null response).
  • Tested locally
  • Updated docs (if needed)
  • Read the contributing guide

@akhilmhdh akhilmhdh requested a review from varonix0 February 2, 2026 10:35
@maidul98
Copy link
Collaborator

maidul98 commented Feb 2, 2026

Snyk checks have passed. No issues have been found so far.

Status Scanner Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 2, 2026

Greptile Overview

Greptile Summary

This PR strengthens the SSE subscription cleanup path by making each client hold an explicit unsubscribe() callback, calling it on permission refresh failure, and doing more robust teardown (clients.delete, keystore removal, removeAllListeners, destroy). It also adjusts lock acquisition TTL and changes the backpressure path to destroy the stream.

The core integration remains: clients register via subscribe(), events flow from projectEventsService.subscribe(...) through permission/registration filtering, then are serialized and pushed to the SSE Readable stream.

Key thing to double-check before merging: the code treats a Node Readable as if it had closed/close() semantics; if those properties don’t exist (or don’t mean what’s expected), heartbeat/ping/refresh gating and close logic can misbehave and undermine the intended leak fix.

Confidence Score: 3/5

  • This PR is likely safe to merge after addressing a stream lifecycle/runtime correctness concern.
  • Main changes are cleanup-focused, but the service relies on Readable.closed/close() semantics that may not exist or may not reflect actual stream state, which could lead to broken heartbeats/pings/permission refresh gating and incomplete cleanup in production. No DB/query surface changes observed.
  • backend/src/ee/services/project-events/project-events-sse-service.ts (stream state and close semantics, backpressure disconnect behavior)

Important Files Changed

Filename Overview
backend/src/ee/services/project-events/project-events-sse-service.ts Adds more SSE connection cleanup (unsubscribe, remove listeners, destroy stream) and changes lock TTL/backpressure behavior; potential runtime issue due to using Readable.close/closed on Readable streams.
backend/src/ee/services/project-events/project-events-sse-types.ts Extends TSSEClient with an unsubscribe() callback so callers can explicitly detach projectEventsService listeners.

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

2 files reviewed, 3 comments

Edit Code Review Agent Settings | Greptile

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 2, 2026

Additional Comments (3)

backend/src/ee/services/project-events/project-events-sse-service.ts
[P0] Readable doesn’t expose closed/close() semantics the way ServerResponse/Writable do, so the repeated checks of client.stream.closed / stream.closed can behave unexpectedly (always falsy) and prevent TTL refresh / pings / cleanup from running as intended.

This matters after this PR because you now rely on stream.closed to skip work and close() to end the connection; on Node streams you generally want stream.destroyed and/or stream.readableEnded.

Also appears at backend/src/ee/services/project-events/project-events-sse-service.ts:154-156, backend/src/ee/services/project-events/project-events-sse-service.ts:229-231, backend/src/ee/services/project-events/project-events-sse-service.ts:333-337.


backend/src/ee/services/project-events/project-events-sse-service.ts
[P2] The lock acquisition TTL jumped from 150ms to 5000ms. If the intent is to avoid lock churn under load, it’s worth double-checking this doesn’t unintentionally increase contention or block other subscribers longer than needed (especially since retryCount: -1 retries indefinitely). If 150ms was too low, consider documenting why 5000 is the right value here.


backend/src/ee/services/project-events/project-events-sse-service.ts
[P1] Destroying the stream on backpressure (!stream.push) will terminate the SSE connection for any temporary slow client and can be triggered by a malicious client that intentionally stops reading (easy to do with SSE). That’s probably acceptable as a protective measure, but it’s a behavioral change from “drop event” to “disconnect client”. If that’s intended, it may be worth logging at warn with project/client context so operators can distinguish normal disconnects from abuse.

@akhilmhdh akhilmhdh merged commit e44200c into main Feb 2, 2026
10 of 11 checks passed
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.

3 participants