Skip to content

Fix unbounded session table growth in directory#614

Merged
amrc-benmorrow merged 6 commits intomainfrom
bk/directory-session-cleanup
Mar 26, 2026
Merged

Fix unbounded session table growth in directory#614
amrc-benmorrow merged 6 commits intomainfrom
bk/directory-session-cleanup

Conversation

@AlexGodbehere
Copy link
Copy Markdown
Contributor

Summary

  • Intern Address objects so that new Address("G","N","D") === new Address("G","N","D"). This fixes this.online Set operations in the directory's MQTT client, which were silently broken because JavaScript Sets use reference equality for objects.
  • Delete old sessions after change-notify completes. The session table was append-only — every birth inserted a row but nothing ever deleted historical sessions. Over years this accumulated millions of rows (and ~3.5x that in schema_used). Now on_session_notify deletes all non-current sessions for a device once it's finished computing the schema diff. Existing installs clean up organically as devices rebirth.
  • Add vitest test framework to acs-directory and js-service-client with 15 tests covering Address interning, session cleanup queries, and find_schemas metric tree traversal.

Test plan

  • cd lib/js-service-client && npm test — 8 Address interning tests pass
  • cd acs-directory && npm test — 7 tests pass (session cleanup + find_schemas)
  • Deploy to staging and verify session table stops growing
  • Verify existing historical sessions are cleaned up as devices rebirth

The Directory service uses Set<Address> for tracking online devices,
but JavaScript Sets use reference equality. By caching Address instances
in a static Map keyed by their string representation, we ensure only one
object exists per unique group/node/device combination, making Set.has()
work correctly.
Add cleanup_old_sessions query that deletes all non-current sessions
for a device, and call it from on_session_notify after the change-notify
has been published. This prevents unbounded accumulation of historical
session rows (which reached 11M in production) while preserving the
previous session long enough to compute the schema diff. Only the
current session's notify handler triggers cleanup, since it runs after
the old session's schemas have been read.
Test that the Address class constructor cache returns the same
instance for identical group/node/device combinations, including
via parse() and parent_node(). Verify Set compatibility and
null/empty device normalisation.
Also add long as an explicit dependency — it was imported directly
by mqttcli.js but only available transitively via sparkplug-payload.
amrc-benmorrow
amrc-benmorrow previously approved these changes Mar 25, 2026
Copy link
Copy Markdown
Contributor

@amrc-benmorrow amrc-benmorrow left a comment

Choose a reason for hiding this comment

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

I'm not 100% sure about the interning but I've approved anyway.

Address interning is a potential memory leak if a service creates
many distinct addresses. Instead, use addr.toString() for the
Set<string> operations on this.online in the directory.
@amrc-benmorrow amrc-benmorrow merged commit d286451 into main Mar 26, 2026
1 check passed
@amrc-benmorrow amrc-benmorrow deleted the bk/directory-session-cleanup branch March 26, 2026 10:35
amrc-benmorrow added a commit that referenced this pull request Mar 26, 2026
This reverts commit d286451, reversing
changes made to e71e1e3.

These changes are not complete. Clearing the session table causes more
notifications, which need to be ignored, and also causes FK errors where
a previous session still references the session to be deleted.
amrc-benmorrow added a commit that referenced this pull request Mar 26, 2026
This reverts commit d286451, reversing
changes made to e71e1e3.

These changes are not complete. Clearing the session table causes more
notifications, which need to be ignored, and also causes FK errors where
a previous session still references the session to be deleted.
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