Restart interrupted update downloads after system wake (#60366)
Follow-up to #60301, which was reverted in #60321. I removed the reqwest part of the fix because it crashed. reqwest's `read_timeout` relies on a tokio timer, but Zed polls HTTP responses on gpui's executor instead of a tokio runtime, so it panicked when the response body was awaited. I'll follow up later by patching our reqwest fork to support the poll behavior we wanted. This fixes the download being stalled since we restart it when the system wakes. I also changed `App::on_system_wake` to return a `gpui::Subscription` to be consistent with gpui's other on-system-event handlers like `on_keyboard_layout_change` and `on_thermal_state_change`. Release Notes: - Fixed Zed update downloads stalling after the system wakes from sleep
This commit is contained in:
1 parent
9a209fdf13
commit
b9e156ba46
2 files changed
+58
-17
No files matched your search
@@ -180,6 +180,7 @@ pub struct AutoUpdater {
|
||||
pending_poll: Option<Task<Option<()>>>,
|
||||
quit_subscription: Option<gpui::Subscription>,
|
||||
update_check_type: UpdateCheckType,
|
||||
_wake_subscription: gpui::Subscription,
|
||||
dismissed_status: Option<AutoUpdateStatus>,
|
||||
}
|
||||
|
||||
@@ -441,6 +442,16 @@ impl AutoUpdater {
|
||||
})
|
||||
.detach();
|
||||
|
||||
// A download or check that was in flight when the machine went to sleep
|
||||
// is almost certainly riding a TCP connection that silently died during
|
||||
// suspend, so it would otherwise appear to stall indefinitely.
|
||||
let wake_subscription = cx.on_system_wake({
|
||||
let this = cx.entity().downgrade();
|
||||
move |cx| {
|
||||
this.update(cx, |this, cx| this.restart_after_wake(cx)).ok();
|
||||
}
|
||||
});
|
||||
|
||||
Self {
|
||||
status: AutoUpdateStatus::Idle,
|
||||
current_version,
|
||||
@@ -448,10 +459,27 @@ impl AutoUpdater {
|
||||
pending_poll: None,
|
||||
quit_subscription,
|
||||
update_check_type: UpdateCheckType::Automatic,
|
||||
_wake_subscription: wake_subscription,
|
||||
dismissed_status: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn restart_after_wake(&mut self, cx: &mut Context<Self>) {
|
||||
// Only network phases can be safely restarted. `Installing` is a local
|
||||
// operation (mounting a dmg, rsync, etc.) that must not be interrupted.
|
||||
if !matches!(
|
||||
self.status,
|
||||
AutoUpdateStatus::Checking | AutoUpdateStatus::Downloading { .. }
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
let check_type = self.update_check_type;
|
||||
self.pending_poll.take();
|
||||
self.status = AutoUpdateStatus::Idle;
|
||||
self.poll(check_type, cx);
|
||||
}
|
||||
|
||||
pub fn start_polling(&self, cx: &mut Context<Self>) -> Task<Result<()>> {
|
||||
let poll_interval =
|
||||
ReleaseChannel::try_global(cx).map_or(POLL_INTERVAL, |channel| match channel {
|
||||
|
||||
+30
-17
@@ -282,23 +282,6 @@ impl Application {
|
||||
self
|
||||
}
|
||||
|
||||
/// Invokes a handler when the system wakes from sleep.
|
||||
pub fn on_system_wake<F>(&self, mut callback: F) -> &Self
|
||||
where
|
||||
F: 'static + FnMut(&mut App),
|
||||
{
|
||||
let this = Rc::downgrade(&self.0);
|
||||
self.0
|
||||
.borrow_mut()
|
||||
.platform
|
||||
.on_system_wake(Box::new(move || {
|
||||
if let Some(app) = this.upgrade() {
|
||||
callback(&mut app.borrow_mut());
|
||||
}
|
||||
}));
|
||||
self
|
||||
}
|
||||
|
||||
/// Returns a handle to the [`BackgroundExecutor`] associated with this app, which can be used to spawn futures in the background.
|
||||
pub fn background_executor(&self) -> BackgroundExecutor {
|
||||
self.0.borrow().background_executor.clone()
|
||||
@@ -717,6 +700,7 @@ pub struct App {
|
||||
pub(crate) keystroke_interceptors: SubscriberSet<(), KeystrokeObserver>,
|
||||
pub(crate) keyboard_layout_observers: SubscriberSet<(), Handler>,
|
||||
pub(crate) thermal_state_observers: SubscriberSet<(), Handler>,
|
||||
pub(crate) system_wake_observers: SubscriberSet<(), Handler>,
|
||||
pub(crate) release_listeners: SubscriberSet<EntityId, ReleaseListener>,
|
||||
pub(crate) global_observers: SubscriberSet<TypeId, Handler>,
|
||||
pub(crate) quit_observers: SubscriberSet<(), QuitHandler>,
|
||||
@@ -845,6 +829,7 @@ impl App {
|
||||
keystroke_interceptors: SubscriberSet::new(),
|
||||
keyboard_layout_observers: SubscriberSet::new(),
|
||||
thermal_state_observers: SubscriberSet::new(),
|
||||
system_wake_observers: SubscriberSet::new(),
|
||||
global_observers: SubscriberSet::new(),
|
||||
quit_observers: SubscriberSet::new(),
|
||||
restart_observers: SubscriberSet::new(),
|
||||
@@ -903,6 +888,18 @@ impl App {
|
||||
}
|
||||
}));
|
||||
|
||||
platform.on_system_wake(Box::new({
|
||||
let app = Rc::downgrade(&app);
|
||||
move || {
|
||||
if let Some(app) = app.upgrade() {
|
||||
let cx = &mut app.borrow_mut();
|
||||
cx.system_wake_observers
|
||||
.clone()
|
||||
.retain(&(), move |callback| (callback)(cx));
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
platform.on_quit(Box::new({
|
||||
let cx = Rc::downgrade(&app);
|
||||
move || {
|
||||
@@ -1339,6 +1336,22 @@ impl App {
|
||||
subscription
|
||||
}
|
||||
|
||||
/// Invokes a handler when the system wakes from sleep.
|
||||
pub fn on_system_wake<F>(&self, mut callback: F) -> Subscription
|
||||
where
|
||||
F: 'static + FnMut(&mut App),
|
||||
{
|
||||
let (subscription, activate) = self.system_wake_observers.insert(
|
||||
(),
|
||||
Box::new(move |cx| {
|
||||
callback(cx);
|
||||
true
|
||||
}),
|
||||
);
|
||||
activate();
|
||||
subscription
|
||||
}
|
||||
|
||||
/// Returns the appearance of the application's windows.
|
||||
pub fn window_appearance(&self) -> WindowAppearance {
|
||||
self.platform.window_appearance()
|
||||
|
||||
Reference in new issue
Block a user