When pull requests sit untouched for days, feedback slows and morale drops. A stalled review queue often signals a process issue rather than lazy teammates. You’ll learn to spot the warning signs, choose a lightweight remedy, and avoid common pitfalls.
Why Reviews Get Stuck
Reviews stall when the workload exceeds capacity or when ownership is unclear. Common failure modes include:
- Reviewers overwhelmed by unrelated tasks
- No clear expectation for response time
- PRs that are too large to review quickly
- Lack of rotation, causing the same people to bear the burden
These patterns create a feedback loop: delayed reviews lead to larger batches, which further delay reviews.
Signals to Watch
Track simple metrics to catch stagnation early.
- Median time from PR creation to first review
- Percentage of PRs older than two days without feedback
- Number of reviewers assigned per PR
If any of these trends worsen, it’s time to intervene.
Strategies to Unblock the Queue
You can apply one or more of the following tactics. Each has strengths and drawbacks.
| Approach | When it helps | Tradeoff |
|---|---|---|
| Manual reminder (e.g., Slack ping) | Small teams, occasional spikes | Relies on human memory, can feel naggy |
| Automated bot that assigns reviewers | Consistent flow, predictable volume | Requires setup and maintenance |
| Rotating reviewer pool | Prevents burnout, spreads knowledge | May reduce deep expertise on niche areas |
Pick the approach that matches your team’s size and culture.
Implementation Example: A Simple Reminder Bot
The following Python script uses the GitHub API to find PRs older than a threshold and posts a friendly comment asking for a review.
import os
import requests
import time
REPO = os.getenv('GITHUB_REPOSITORY') # e.g., 'org/repo'
TOKEN = os.getenv('GH_TOKEN')
THRESHOLD_HOURS = int(os.getenv('STALE_HOURS', '24'))
headers = {
'Authorization': f'token {TOKEN}',
'Accept': 'application/vnd.github+json'
}
def get_open_prs():
url = f'https://api.github.com/repos/{REPO}/pulls?state=open'
resp = requests.get(url, headers=headers)
resp.raise_for_status()
return resp.json()
def post_comment(pr_number, body):
url = f'https://api.github.com/repos/{REPO}/issues/{pr_number}/comments'
payload = {'body': body}
resp = requests.post(url, json=payload, headers=headers)
resp.raise_for_status()
def main():
now = time.time()
for pr in get_open_prs():
created = pr['created_at']
# GitHub returns ISO 8601; parse simply
from datetime import datetime, timezone
created_dt = datetime.fromisoformat(created.replace('Z', '+00:00'))
age_hours = (now - created_dt.timestamp()) / 3600
if age_hours > THRESHOLD_HOURS:
message = (
f'Hey team, this PR has been open for {int(age_hours)} hours. '
'Could someone please take a look when you have a moment?'
)
post_comment(pr['number'], message)
print(f'Posted reminder on PR #{pr["number"]}')
if __name__ == '__main__':
main()
This script is intentionally minimal: it fetches open PRs, checks their age, and adds a comment if they exceed the threshold. By keeping the logic straightforward, you can run it as a cron job or integrate it into a CI pipeline without heavy dependencies.
Automation with GitHub Actions
You can schedule the script to run every hour using a workflow file.
name: Stale PR Reminder
on:
schedule:
- cron: '0 * * * *' # every hour
workflow_dispatch:
jobs:
remind:
runs-on: ubuntu-latest
env:
GITHUB_REPOSITORY: ${{ github.repository }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
STALE_HOURS: '24'
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install dependencies
run: pip install requests
- name: Run reminder script
run: python .github/scripts/stale_reminder.py
The workflow uses the default GITHUB_TOKEN, which has permission to comment on PRs in the same repository. Adjust the cron expression if you need a different frequency.
Tradeoffs and Pitfalls
- Over‑reminding: If the threshold is too low, you’ll spam reviewers and they may start ignoring the messages. Start with a higher threshold (e.g., 24 hours) and tune based on team feedback.
- False sense of security: Automation does not replace a culture of timely feedback. Use the bot as a safety net, not a substitute for explicit expectations.
-
Permission limits: Fine‑grained tokens may lack the
issues:writescope needed to comment. Ensure your token or the defaultGITHUB_TOKENincludes that permission. - Large PRs: The bot cannot assess size; consider coupling it with a label‑based system that flags huge changes for optional splitting.
Key Takeaways
- Track median review time and age of open PRs to detect stalls early.
- Choose a remedy that matches your team’s scale: manual reminders for small groups, bots for steady flow, rotation for burnout prevention.
- Keep automation simple and observable; start with a conservative threshold and adjust.
- Remember that tools support, but do not replace, clear expectations and a helpful mindset.
Source
If we do not stop to help each other, what do we become? – I expanded the source’s reflection on mutual aid into concrete, actionable steps for maintaining healthy code review practices.
Support this work
These write-ups are researched and published with no paywall, sponsor, or tracking. If one saved you an afternoon, a small tip keeps them coming.
USDT, USDC or USDD · TRC-20 (Tron)
TFTNsfyomKrnUutRjBTGVULp19ByW29KbY
Top comments (0)