Skip to content

feat(async): Add daily task to archive stale Slack channels#206

Open
rgibert wants to merge 6 commits into
mainfrom
rgibert/archive-stale-channels
Open

feat(async): Add daily task to archive stale Slack channels#206
rgibert wants to merge 6 commits into
mainfrom
rgibert/archive-stale-channels

Conversation

@rgibert
Copy link
Copy Markdown
Member

@rgibert rgibert commented May 22, 2026

Add a django-q2 scheduled task that runs daily to find bot-created Slack channels where the workspace retention policy has deleted all message history. For each stale channel, posts an archival notice and archives the channel.

The task queries ExternalLink records (type=SLACK) to find channels Firetower created, checks each via conversations_info and conversations_history(limit=1), and archives any channel with zero remaining messages. Per-channel errors are isolated so one failure doesn't abort the run. If the Slack client is unavailable (no bot token), the task disables its own schedule.

SlackService changes: added archive_channel(), a limit parameter to get_channel_history (avoids paginating all messages when we only need to check existence), and is_archived to get_channel_info.

Resolves RELENG-20

Agent transcript: https://claudescope.sentry.dev/share/onjkTdIu9bD3cgBvGExA2meMCtHFG8S8cpHdLO1DEk8

Add a django-q2 scheduled task that runs daily to find bot-created
Slack channels where the workspace retention policy has deleted all
message history. For each stale channel, posts an archival notice
and archives the channel.

Changes:
- Add archive_channel() method and limit param to get_channel_history
  on SlackService
- Add archive_stale_channels task with per-channel error isolation
- Self-disables the schedule if Slack client is unavailable
- Add is_archived to get_channel_info return dict
- Data migration to register the schedule

Co-Authored-By: Claude <noreply@anthropic.com>

Agent transcript: https://claudescope.sentry.dev/share/SeyXSRtESuCIjsSjmOGgO3MM_MZHcZftkU8Td81uFP8
@rgibert rgibert self-assigned this May 22, 2026
@linear-code
Copy link
Copy Markdown

linear-code Bot commented May 22, 2026

RELENG-20

Comment thread src/firetower/incidents/tasks.py Outdated
Comment thread src/firetower/incidents/tasks.py Outdated
Comment thread src/firetower/incidents/tasks.py
Comment thread src/firetower/incidents/tasks.py
Three bugs fixed:

1. get_channel_history(limit=1) swallowed exceptions and returned [],
   which the task treated as "no messages" and archived active channels.
   Now exceptions propagate and the per-channel handler skips the channel.

2. The archival notice was posted before calling archive_channel. If
   archiving failed, the notice remained in the channel misleading users.
   Now the notice timestamp is captured and the message is deleted on
   failed archive.

3. A failed archive after a successful notice post would permanently
   prevent future archiving -- the bot's own notice became "history"
   causing the channel to be skipped on every subsequent run. Fixed by
   deleting the notice on failure (issue 2 fix).

Also adds SlackService.delete_message() wrapping chat_delete.

Co-Authored-By: Claude <noreply@anthropic.com>

Agent transcript: https://claudescope.sentry.dev/share/Sq3ianFbApEXKqxUP2-TSgUOWGcOaf_XYnSDxYWDsKo
Comment thread src/firetower/incidents/tasks.py Outdated
Comment thread src/firetower/incidents/tasks.py
Add a 2-second delay between channels to stay under Slack's Tier 3
rate limit (~50 req/min). Without this, workspaces with >25 incident
channels would routinely hit rate limits on every daily run.

Also skip archiving when post_message fails (returns None) instead of
archiving the channel with no warning to users.

Co-Authored-By: Claude <noreply@anthropic.com>

Agent transcript: https://claudescope.sentry.dev/share/tRJBNFSwD_KABR2S1OuvR2T7oKVr_Hwgtfk-OUCIRyw
Comment thread src/firetower/incidents/tasks.py
Comment thread src/firetower/integrations/services/slack.py
Comment thread src/firetower/integrations/services/slack.py
Two issues fixed:

1. If delete_message failed after a failed archive, the bot's own notice
   remained as the only message in the channel, causing every future run
   to skip it permanently. Now the history check uses limit=5 and filters
   out bot messages (by bot_id), so leftover bot notices don't prevent
   future archival attempts.

2. If archive_channel raised a non-SlackApiError (e.g. ConnectionError),
   the exception hit the outer handler which never called delete_message.
   Restructured so the archive attempt has its own try/except that always
   reaches the notice cleanup on any failure mode.

Co-Authored-By: Claude <noreply@anthropic.com>

Agent transcript: https://claudescope.sentry.dev/share/niq15OUwbdrxpEKAdaoIszEmbWDRe369PsqC1_qlA9Q
Comment thread src/firetower/incidents/tests/test_tasks.py
Comment thread src/firetower/incidents/tasks.py
rgibert added 2 commits May 22, 2026 12:06
The previous bot_id filter ignored messages from any bot, which could
skip messages from other integrations that legitimately indicate
channel activity. Now uses auth_test to resolve the bot's own identity
and only filters messages matching that specific bot_id. Messages from
other bots are treated as real activity.

Also adds a cached bot_id property to SlackService backed by auth_test,
called once per task run.

Co-Authored-By: Claude <noreply@anthropic.com>

Agent transcript: https://claudescope.sentry.dev/share/l1u4EK0km7aDME7RkCQJB5vxCzc3c61oPc4oOSn7rws
@rgibert rgibert marked this pull request as ready for review May 22, 2026 17:46
@rgibert rgibert requested a review from a team as a code owner May 22, 2026 17:46
Comment thread src/firetower/integrations/services/slack.py
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 04dfff0. Configure here.

Comment thread src/firetower/integrations/services/slack.py
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.

1 participant