Skip to content

Fix RSS/Atom feed errors appearing as new entries on every poll#667

Merged
codingjoe merged 8 commits intomainfrom
copilot/fix-rss-feed-date-issue
Mar 1, 2026
Merged

Fix RSS/Atom feed errors appearing as new entries on every poll#667
codingjoe merged 8 commits intomainfrom
copilot/fix-rss-feed-date-issue

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Feb 26, 2026

Feed error entries used timezone.now() as their publish date, causing feed readers to flag the same incident as new on every poll. For proxied status pages (AWS, GCP, Atlassian-based, etc.), the incident date from the source feed is now preserved.

Changes

  • HealthCheckException: Added an optional timestamp kwarg (defaulting to timezone.now() via an explicit None check) so every error always carries a timestamp and feed rendering can use result.error.timestamp directly.
  • StatusPageWarning: New StatusPageWarning(ServiceWarning) exception type for RSS/Atom and Atlassian status-page incidents. Inherits the timestamp kwarg from HealthCheckException without overriding __init__.
  • contrib/rss.py: Introduced _recent_incidents() generator that calls _extract_date() once per entry (fixing a previous double-loop) and yields (entry, date) pairs. The most recent incident date is passed as timestamp to StatusPageWarning.
  • contrib/atlassian.py: _fetch_incidents() uses incident["updated_at"] directly (per the Atlassian Status Page API spec) and filters out incidents with status of "resolved" or "postmortem". The defensive _parse_incident_timestamp helper and its try/except are removed.
  • views.py: _render_feed uses result.error.timestamp directly — the timestamp is always set on every error, defaulting to current time for generic errors and carrying the source incident date for status-page warnings.
# Before: every poll emits a "new" feed item with current time
published_at = timezone.now() if result.error else epoch

# After: source date is preserved; falls back to now() for generic errors
published_at = result.error.timestamp if result.error else epoch
Original prompt

This section details on the original issue you should resolve

<issue_title>🐛 RSS feed errors show up as new on every pull of the feed</issue_title>
<issue_description>### Bug Description

If an error is found, the RSS/Atom feed entry will use the current date. This will cause the feed to have a "new" item on every poll.

This behavior doesn't make sense for proxied status updates from other status pages.

Expected Behavior

It should transfer the date of the source status page and propagate it into the RSS/Atom feed.

We can add a new exception, which carries the feed data including the date. The health check view can use the exception data to render the feed correctly.

Version

4.0.6

Stack trace

No response

Steps to Reproduce

No response</issue_description>

Comments on the Issue (you are @copilot in this section)

Custom agent used: SuperJoe
CodingJoe's digital clone following his coding guidelines and best practices.


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

When an RSS/Atom feed health check detects an incident, the resulting
ServiceWarning now carries the most recent incident's publish date as its
timestamp. The feed renderer uses that timestamp (falling back to the
current time) so feed readers don't treat the same incident as a new
entry on every poll.

Co-authored-by: codingjoe <1772890+codingjoe@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix RSS feed errors appearing as new items on every pull Fix RSS/Atom feed errors appearing as new entries on every poll Feb 26, 2026
Copilot AI requested a review from codingjoe February 26, 2026 20:59
Copy link
Copy Markdown
Owner

@codingjoe codingjoe left a comment

Choose a reason for hiding this comment

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

@copilot this needs to be added to the atlassian tests too.

Comment thread health_check/contrib/rss.py Outdated
Comment thread health_check/exceptions.py
… in rss.py, add Atlassian timestamp support

- Add StatusPageWarning(ServiceWarning) exception type carrying an optional source
  timestamp, instead of adding timestamp to the base HealthCheckException
- Fix rss.py double-loop: _recent_incidents() generator calls _extract_date() once
  per entry, yielding (entry, date) pairs; run() consumes these to build both the
  message and max timestamp in a single pass
- Atlassian: _fetch_incidents() yields (message, timestamp) tuples via new
  _parse_incident_timestamp(); run() raises StatusPageWarning with the most recent
  incident timestamp
- views.py uses getattr(result.error, 'timestamp', None) for safety
- Update all tests to use StatusPageWarning; add Atlassian timestamp propagation test

Co-authored-by: codingjoe <1772890+codingjoe@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Feb 26, 2026

@copilot this needs to be added to the atlassian tests too.

Done in 3c003ed. _fetch_incidents() now yields (message, timestamp) tuples via the new _parse_incident_timestamp() helper (tries started_atcreated_atupdated_at). run() raises StatusPageWarning with the most recent incident timestamp. A corresponding test (test_check_status__incident_carries_source_timestamp) was added to TestFlyIo.

@codingjoe
Copy link
Copy Markdown
Owner

pre-commit.ci run

@codecov
Copy link
Copy Markdown

codecov Bot commented Mar 1, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.74%. Comparing base (7bfd8dc) to head (736d7ad).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #667   +/-   ##
=======================================
  Coverage   99.73%   99.74%           
=======================================
  Files          13       13           
  Lines         768      772    +4     
=======================================
+ Hits          766      770    +4     
  Misses          2        2           
Flag Coverage Δ
python-3.10-django-5.2 50.38% <21.05%> (-0.01%) ⬇️
python-3.10-django-5.2-celery 55.18% <21.05%> (-0.03%) ⬇️
python-3.10-django-5.2-kafka 53.36% <21.05%> (-0.02%) ⬇️
python-3.10-django-5.2-psutil 61.78% <21.05%> (-0.07%) ⬇️
python-3.10-django-5.2-rabbitmq 53.10% <21.05%> (-0.02%) ⬇️
python-3.10-django-5.2-redis 56.60% <21.05%> (-0.04%) ⬇️
python-3.10-django-5.2-rss 70.07% <100.00%> (+0.15%) ⬆️
python-3.11-django-5.2 50.38% <21.05%> (-0.01%) ⬇️
python-3.12-django-5.2 50.38% <21.05%> (-0.01%) ⬇️
python-3.12-django-6.0 50.38% <21.05%> (-0.01%) ⬇️
python-3.13-django-5.2 50.38% <21.05%> (-0.01%) ⬇️
python-3.13-django-6.0 50.38% <21.05%> (-0.01%) ⬇️
python-3.14-django-5.2 50.65% <21.05%> (-0.01%) ⬇️
python-3.14-django-5.2-celery 55.46% <21.05%> (-0.03%) ⬇️
python-3.14-django-5.2-kafka 53.51% <21.05%> (-0.02%) ⬇️
python-3.14-django-5.2-psutil 62.10% <21.05%> (-0.07%) ⬇️
python-3.14-django-5.2-rabbitmq 53.25% <21.05%> (-0.02%) ⬇️
python-3.14-django-5.2-redis 56.90% <21.05%> (-0.04%) ⬇️
python-3.14-django-5.2-rss 71.09% <100.00%> (+0.15%) ⬆️
python-3.14-django-6.0 50.65% <21.05%> (-0.01%) ⬇️

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

☔ View full report in Codecov by Sentry.
📢 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.

Copy link
Copy Markdown
Owner

@codingjoe codingjoe left a comment

Choose a reason for hiding this comment

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

@copilot atlassian.py L93 isn't covered yet.

Please add the optional timestamp to the base exception, to avoid the getattr(), but keep the specific implementation for Atom/RSS incidents. default to timezone.now() if no time was passed.

- HealthCheckException now accepts optional `timestamp` kwarg defaulting to
  datetime.datetime.now(tz=utc) so every error always carries a timestamp
- views.py can now use result.error.timestamp directly (no getattr), and the
  unused django.utils.timezone import is removed
- StatusPageWarning simplified to just super().__init__(message, timestamp=timestamp)
- Add test_check_status__incident_with_invalid_timestamp in TestFlyIo to cover
  the except ValueError branch in _parse_incident_timestamp (atlassian.py L93)
- Update exception tests: timestamp defaults to now, not None

Co-authored-by: codingjoe <1772890+codingjoe@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Mar 1, 2026

@copilot atlassian.py L93 isn't covered yet.

Please add the optional timestamp to the base exception, to avoid the getattr(), but keep the specific implementation for Atom/RSS incidents. default to t...

Done in 64e3e10:

  • HealthCheckException.__init__ now accepts an optional timestamp kwarg that defaults to datetime.datetime.now(tz=utc), so every error always carries a timestamp and views.py uses result.error.timestamp directly (removed getattr() and the unused timezone import).
  • StatusPageWarning simplified to just super().__init__(message, timestamp=timestamp).
  • atlassian.py L93 is now covered by test_check_status__incident_with_invalid_timestamp, which verifies that an incident with a non-ISO timestamp falls back to current time.

Copilot AI requested a review from codingjoe March 1, 2026 15:29
Copy link
Copy Markdown
Owner

@codingjoe codingjoe left a comment

Choose a reason for hiding this comment

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

Comment thread health_check/exceptions.py Outdated
Comment thread health_check/exceptions.py Outdated
…atusPageWarning.__init__

- Replace bare `datetime.datetime.now(tz=utc)` with `timezone.now()` in
  HealthCheckException as requested
- Remove the redundant __init__ override in StatusPageWarning — it inherits
  the timestamp kwarg directly from HealthCheckException
- Update tests to use timezone.now() for timestamp-default assertions

Co-authored-by: codingjoe <1772890+codingjoe@users.noreply.github.com>
Copilot AI requested a review from codingjoe March 1, 2026 15:43
@codingjoe codingjoe marked this pull request as ready for review March 1, 2026 15:48
Copilot AI review requested due to automatic review settings March 1, 2026 15:48
Copy link
Copy Markdown
Contributor

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

This PR fixes RSS/Atom feeds repeatedly surfacing the same upstream status-page incident as a “new” entry on every poll by propagating the incident’s source timestamp through health check exceptions into feed rendering.

Changes:

  • Add a timestamp attribute to HealthCheckException (defaulting to timezone.now()), plus a StatusPageWarning type for status-page sourced warnings.
  • Update RSS and Atlassian status-page checks to raise StatusPageWarning with the most recent incident timestamp.
  • Update feed rendering and tests to ensure RSS/Atom items use the exception timestamp instead of “current time”.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
health_check/exceptions.py Adds timestamp support on HealthCheckException and introduces StatusPageWarning.
health_check/views.py Uses result.error.timestamp for RSS/Atom pubdate/updateddate.
health_check/contrib/rss.py Raises StatusPageWarning with max incident date; refactors recent-incident iteration.
health_check/contrib/atlassian.py Parses incident timestamps and raises StatusPageWarning with the most recent timestamp.
tests/test_exceptions.py Adds unit tests for exception timestamp defaulting/storage and StatusPageWarning behavior.
tests/test_views.py Adds regression tests asserting feed dates come from exception timestamps when provided.
tests/contrib/test_rss.py Verifies RSS incident warnings carry the most recent source pubDate timestamp.
tests/contrib/test_atlassian.py Verifies Atlassian incident warnings carry source timestamps and covers invalid timestamp parsing.

Comment thread health_check/exceptions.py Outdated
Copy link
Copy Markdown
Owner

@codingjoe codingjoe left a comment

Choose a reason for hiding this comment

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

@copilot This code is too defensive. The atlassian API is stable. If you don't know the response data structure fetch the spec here: https://status.atlassian.com/api

Comment thread health_check/contrib/atlassian.py Outdated
Comment thread health_check/contrib/atlassian.py Outdated
… resolved incidents

- exceptions.py: use explicit None check for timestamp default to avoid masking
  falsy-but-valid datetime values
- atlassian.py: drop _parse_incident_timestamp helper; use updated_at directly
  (always present per API spec); filter out resolved and postmortem incidents
- tests: update incident fixtures with status/updated_at, replace invalid-timestamp
  test with test_check_status__resolved_incidents_are_filtered

Co-authored-by: codingjoe <1772890+codingjoe@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Mar 1, 2026

Just as a heads up, I was blocked by some firewall rules while working on your feedback. Expand below for details.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • status.atlassian.com
    • Triggering command: /home/REDACTED/work/_temp/ghcca-node/node/bin/node /home/REDACTED/work/_temp/ghcca-node/node/bin/node --enable-source-maps /home/REDACTED/work/_temp/copilot-developer-action-main/dist/index.js (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Copilot AI requested a review from codingjoe March 1, 2026 15:59
@codingjoe codingjoe merged commit c13c109 into main Mar 1, 2026
34 checks passed
@codingjoe codingjoe deleted the copilot/fix-rss-feed-date-issue branch March 1, 2026 16:01
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.

🐛 RSS feed errors show up as new on every pull of the feed

3 participants