Skip to content

Fix Pulse flusher state writes#2

Merged
Alcheri merged 4 commits into
Limnoria-Pulsefrom
main
May 2, 2026
Merged

Fix Pulse flusher state writes#2
Alcheri merged 4 commits into
Limnoria-Pulsefrom
main

Conversation

@Alcheri
Copy link
Copy Markdown
Owner

@Alcheri Alcheri commented May 2, 2026

Pull Request

Summary

Fixes Pulse’s Limnoria flusher failure on Borg where json.dump(..., sort_keys=True) raised:

TypeError: '<' not supported between instances of 'dict' and 'dict'

Changes

  • Removed sort_keys=True from Pulse JSON state writes so mixed/unorderable keys do not break flushing.
  • Added non-fatal handling for JSON serialisation errors during state writes.
  • Added locked storage snapshots before flushing feed/seen state.
  • Tightened storage locking around feed and seen state mutations.
  • Added regression tests for:
    • isolated storage snapshots
    • non-raising flusher serialisation failures
    • JSON writes with unsortable key types

Verification

  • python -m pytest -q: 19 passed
  • python -m py_compile ...: passed
  • tracked file-by-file Black check: passed
  • git diff --check: passed

@github-advanced-security
Copy link
Copy Markdown

You are seeing this message because GitHub Code Scanning has recently been set up for this repository, or this pull request contains the workflow file for the Code Scanning tool.

What Enabling Code Scanning Means:

  • The 'Security' tab will display more code scanning analysis results (e.g., for the default branch).
  • Depending on your configuration and choice of analysis tool, future pull requests will be annotated with code scanning analysis results.
  • You will be able to see the analysis results for the pull request's branch on this overview once the scans have completed and the checks have passed.

For more information about GitHub Code Scanning, check out the documentation.

Copilot AI review requested due to automatic review settings May 2, 2026 06:01
@Alcheri Alcheri merged commit 26b6642 into Limnoria-Pulse May 2, 2026
15 checks passed
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Fixes Pulse state flusher failures caused by JSON key sorting on mixed/unorderable key types, and improves thread-safety around state persistence.

Changes:

  • Stop sorting JSON keys on state writes and make JSON serialisation failures non-fatal (log + continue).
  • Add locked storage snapshots for flushes and tighten locking around feed/seen mutations.
  • Add regression tests and repository maintenance/CI hygiene files (labeler, templates, contributing doc).

Reviewed changes

Copilot reviewed 7 out of 8 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
plugin.py Removes sort_keys=True, adds non-fatal JSON serialisation handling, flushes via storage snapshot.
storage.py Adds deep-copied snapshot method and expands locking/copying for feed/seen state access.
test.py Adds regression tests for snapshot isolation and non-raising flush/write behaviour.
docs/CONTRIBUTING.md Adds contributing/recognition guidance.
.gitignore Removes ignored To-Do file entry.
.github/workflows/labeler.yml Adds PR labeler workflow.
.github/labeler.yml Adds label rules for common areas (plugin/docs/tests/etc.).
.github/PULL_REQUEST_TEMPLATE.md Adds PR template checklist and guidance.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread plugin.py
Comment on lines 129 to +133
try:
with open(path, "w", encoding="utf-8") as handle:
json.dump(data, handle, indent=2, sort_keys=True)
json.dump(data, handle, indent=2)
except (TypeError, ValueError) as e:
log.warning(f"Pulse: could not serialise {path}: {e}")
Comment thread storage.py
Comment on lines +56 to 60
for name, record in self.feeds[LEGACY_FEEDS_NETWORK].items()
if looks_like_feed_record(record)
}
return self.feeds.setdefault(network, {})

Comment thread storage.py
Comment on lines 61 to +65
def get_feed_record(self, network, name):
return self.network_feeds(network).get(callbacks.canonicalName(name))
record = self.network_feeds(network).get(callbacks.canonicalName(name))
if record is None:
return None
return dict(record)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants