Skip to content

Improve UI responsiveness during widget refresh #2118

Description

@Seanstoppable

Problem

When a widget refreshes (either on a timer or via the r keyboard shortcut), the UI can become unresponsive while waiting for API calls to complete. This is because Refresh() runs synchronously — the widget's scheduler goroutine (or the tview event loop, in the case of keyboard-triggered refresh) is blocked on network I/O until all HTTP calls finish.

This is noticeable on widgets that make multiple or slow API calls (e.g. GitHub, NewRelic, GitLab, Jira).

Proposed approach

1. Run keyboard-triggered refresh in a background goroutine

Currently, pressing r calls widget.Refresh() directly on the tview input handler goroutine. Wrapping this in a goroutine would keep the UI responsive:

widget.InitializeRefreshKeyboardControl(func() {
    go widget.Refresh()
})

This could be done once in KeyboardWidget.InitializeRefreshKeyboardControl() so all widgets benefit.

2. Add a context.WithTimeout at the scheduler level

Individual modules shouldn't need to manage their own timeouts. app.Schedule() could wrap each Refresh() call with a deadline:

ctx, cancel := context.WithTimeout(context.Background(), refreshTimeout)
defer cancel()
widget.Refresh(ctx)

This would require updating the Wtfable interface to accept a context, which is a larger change but would protect against any single module hanging the scheduler.

3. Ensure content() functions are always CPU-only

Establish as a project convention that the function passed to Redraw() should never do network I/O. All data fetching should happen in Refresh(), with results cached for content() to read. This was addressed for the GitHub widget in #2117 but other modules (e.g. NewRelic) have the same pattern.

Modules affected

A quick scan shows these modules make HTTP calls without timeouts or have network calls in their display path:

  • NewReliccontent() makes HTTP calls directly
  • DigitalOcean — keyboard handlers call API methods synchronously
  • Transmission — keyboard handlers call API methods synchronously
  • PagerDuty, AzureDevOps, DevTo, Gerrit — use context.Background() without timeouts

Impact

This is a quality-of-life improvement. The app remains functional but feels sluggish when widgets are refreshing, especially with slow or rate-limited APIs.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions