Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 27 additions & 5 deletions internal/github/pr.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ type cacheEntry struct {
fetchedAt time.Time
}

const cacheTTL = 15 * time.Second
const cacheTTL = 90 * time.Second

// NewPRCache creates a new PR cache.
func NewPRCache() *PRCache {
Expand Down Expand Up @@ -144,6 +144,14 @@ func fetchPRInfo(repoDir, branchName string) *PRInfo {

output, err := cmd.Output()
if err != nil {
// Check if this is a rate limit error
if exitErr, ok := err.(*exec.ExitError); ok {
stderr := string(exitErr.Stderr)
if strings.Contains(stderr, "rate limit") || strings.Contains(stderr, "API rate limit") {
// Return nil on rate limit (cache will be used if available)
return nil
}
}
// No PR exists for this branch, timeout, or other error
return nil
}
Expand Down Expand Up @@ -330,6 +338,14 @@ func FetchAllPRsForRepo(repoDir string) map[string]*PRInfo {

output, err := cmd.Output()
if err != nil {
// Check if this is a rate limit error
if exitErr, ok := err.(*exec.ExitError); ok {
stderr := string(exitErr.Stderr)
if strings.Contains(stderr, "rate limit") || strings.Contains(stderr, "API rate limit") {
// Return nil to signal rate limit hit (caller can use cached data)
return nil
}
}
return result
}

Expand All @@ -355,8 +371,8 @@ func FetchAllPRsForRepo(repoDir string) map[string]*PRInfo {
"--limit", "20")
cmd2.Dir = repoDir

output2, err := cmd2.Output()
if err == nil {
output2, err2 := cmd2.Output()
if err2 == nil {
var mergedPRs []ghPRListResponse
if json.Unmarshal(output2, &mergedPRs) == nil {
for _, pr := range mergedPRs {
Expand All @@ -369,6 +385,12 @@ func FetchAllPRsForRepo(repoDir string) map[string]*PRInfo {
}
}
}
} else if exitErr, ok := err2.(*exec.ExitError); ok {
stderr := string(exitErr.Stderr)
if strings.Contains(stderr, "rate limit") || strings.Contains(stderr, "API rate limit") {
// Hit rate limit, skip closed PR fetch too
return result
}
}

// Also fetch recently closed PRs (last 10) to catch closures
Expand All @@ -381,8 +403,8 @@ func FetchAllPRsForRepo(repoDir string) map[string]*PRInfo {
"--limit", "10")
cmd3.Dir = repoDir

output3, err := cmd3.Output()
if err == nil {
output3, err3 := cmd3.Output()
if err3 == nil {
var closedPRs []ghPRListResponse
if json.Unmarshal(output3, &closedPRs) == nil {
for _, pr := range closedPRs {
Expand Down
4 changes: 2 additions & 2 deletions internal/ui/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -940,7 +940,7 @@ func (m *AppModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
}

case prRefreshTickMsg:
// Periodically refresh PR info (every 15 seconds)
// Periodically refresh PR info (every 60 seconds)
// Always refresh regardless of view - PR state is persisted to DB
// so it stays current even when navigating between views
cmds = append(cmds, m.refreshAllPRs())
Expand Down Expand Up @@ -4174,7 +4174,7 @@ func (m *AppModel) focusTick() tea.Cmd {
}

func (m *AppModel) prRefreshTick() tea.Cmd {
return tea.Tick(15*time.Second, func(t time.Time) tea.Msg {
return tea.Tick(60*time.Second, func(t time.Time) tea.Msg {
return prRefreshTickMsg(t)
})
}
Expand Down