1
1
mirror of https://github.com/wez/wezterm.git synced 2024-12-24 13:52:55 +03:00

gui: Avoid 450ms delay on startup(!)

In the case that the published symlink is stale, our default
client connection logic was to retry connecting with backoff
to give a newly spawned server a chance to startup.

In the context of a newly launched gui process checking to see
if an existing gui process can serve the same request, we don't
need to give it any grace: it will either answer immediately
or be deemed not useful.

This commit limits us to a single connection attempt in the case
where we're not automatically starting the server, which in turn
constrains the overhead to something in the order of microseconds
rather than nearly 0.5 seconds.

While we're in here, I noticed that if we thought we had a socket
to try and that failed, we'd always try to publish a new symlink.
However, if we failed due to mismatched version info, we shouldn't
publish over the top of the already running instance.

refs: #1529
This commit is contained in:
Wez Furlong 2022-01-10 20:31:01 -07:00
parent d1018c37ff
commit 58d969e77c
3 changed files with 26 additions and 12 deletions

View File

@ -164,12 +164,19 @@ fn process_unilateral(
local_domain_id: Option<DomainId>, local_domain_id: Option<DomainId>,
decoded: DecodedPdu, decoded: DecodedPdu,
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
let local_domain_id = local_domain_id.ok_or_else(|| { let local_domain_id = match local_domain_id {
anyhow::anyhow!( Some(id) => id,
None => {
// FIXME: We currently get a bunch of these; we'll need
// to do something to advise the server when we want them.
// For now, we just ignore them.
log::trace!(
"client doesn't have a real local domain, \ "client doesn't have a real local domain, \
so unilateral message cannot be processed by it" so unilateral message cannot be processed by it"
) );
})?; return Ok(());
}
};
if let Some(pane_id) = decoded.pdu.pane_id() { if let Some(pane_id) = decoded.pdu.pane_id() {
promise::spawn::spawn_into_main_thread(async move { promise::spawn::spawn_into_main_thread(async move {
process_unilateral_inner(pane_id, local_domain_id, decoded) process_unilateral_inner(pane_id, local_domain_id, decoded)
@ -281,6 +288,7 @@ async fn client_thread_async(
pub fn unix_connect_with_retry( pub fn unix_connect_with_retry(
target: &UnixTarget, target: &UnixTarget,
just_spawned: bool, just_spawned: bool,
max_attempts: Option<u64>,
) -> anyhow::Result<UnixStream> { ) -> anyhow::Result<UnixStream> {
let mut error = None; let mut error = None;
@ -288,7 +296,9 @@ pub fn unix_connect_with_retry(
std::thread::sleep(std::time::Duration::from_millis(200)); std::thread::sleep(std::time::Duration::from_millis(200));
} }
for iter in 0..10 { let max_attempts = max_attempts.unwrap_or(10);
for iter in 0..max_attempts {
if iter > 0 { if iter > 0 {
std::thread::sleep(std::time::Duration::from_millis(iter * 10)); std::thread::sleep(std::time::Duration::from_millis(iter * 10));
} }
@ -561,7 +571,9 @@ impl Reconnectable {
ui.output_str(&format!("Connect to {:?}\n", target)); ui.output_str(&format!("Connect to {:?}\n", target));
log::trace!("connect to {:?}", target); log::trace!("connect to {:?}", target);
let stream = match unix_connect_with_retry(&target, false) { let max_attempts = if no_auto_start { Some(1) } else { None };
let stream = match unix_connect_with_retry(&target, false, max_attempts) {
Ok(stream) => stream, Ok(stream) => stream,
Err(e) => { Err(e) => {
if no_auto_start || unix_dom.no_serve_automatically || !initial { if no_auto_start || unix_dom.no_serve_automatically || !initial {
@ -603,7 +615,7 @@ impl Reconnectable {
} }
}); });
unix_connect_with_retry(&target, true).with_context(|| { unix_connect_with_retry(&target, true, None).with_context(|| {
format!("(after spawning server) failed to connect to {:?}", target) format!("(after spawning server) failed to connect to {:?}", target)
})? })?
} }

View File

@ -417,7 +417,7 @@ impl Publish {
} }
pub fn try_spawn( pub fn try_spawn(
&self, &mut self,
cmd: Option<CommandBuilder>, cmd: Option<CommandBuilder>,
config: &ConfigHandle, config: &ConfigHandle,
) -> anyhow::Result<bool> { ) -> anyhow::Result<bool> {
@ -437,12 +437,14 @@ impl Publish {
let vers = client.verify_version_compat(&mut ui).await?; let vers = client.verify_version_compat(&mut ui).await?;
if vers.executable_path != std::env::current_exe().context("resolve executable path")? { if vers.executable_path != std::env::current_exe().context("resolve executable path")? {
*self = Publish::NoConnectNoPublish;
anyhow::bail!( anyhow::bail!(
"Running GUI is a different executable from us, will start a new one"); "Running GUI is a different executable from us, will start a new one");
} }
if vers.config_file_path if vers.config_file_path
!= std::env::var_os("WEZTERM_CONFIG_FILE").map(Into::into) != std::env::var_os("WEZTERM_CONFIG_FILE").map(Into::into)
{ {
*self = Publish::NoConnectNoPublish;
anyhow::bail!( anyhow::bail!(
"Running GUI has different config from us, will start a new one" "Running GUI has different config from us, will start a new one"
); );
@ -567,7 +569,7 @@ fn run_terminal_gui(opts: StartCommand) -> anyhow::Result<()> {
// First, let's see if we can ask an already running wezterm to do this. // First, let's see if we can ask an already running wezterm to do this.
// We must do this before we start the gui frontend as the scheduler // We must do this before we start the gui frontend as the scheduler
// requirements are different. // requirements are different.
let publish = Publish::resolve(&mux, &config, opts.always_new_process); let mut publish = Publish::resolve(&mux, &config, opts.always_new_process);
log::trace!("{:?}", publish); log::trace!("{:?}", publish);
if publish.try_spawn(cmd.clone(), &config)? { if publish.try_spawn(cmd.clone(), &config)? {
return Ok(()); return Ok(());

View File

@ -578,7 +578,7 @@ async fn run_cli_async(config: config::ConfigHandle, cli: CliCommand) -> anyhow:
Mux::set_mux(&mux); Mux::set_mux(&mux);
let unix_dom = config.unix_domains.first().unwrap(); let unix_dom = config.unix_domains.first().unwrap();
let target = unix_dom.target(); let target = unix_dom.target();
let stream = unix_connect_with_retry(&target, false)?; let stream = unix_connect_with_retry(&target, false, None)?;
// Spawn a thread to pull data from the socket and write // Spawn a thread to pull data from the socket and write
// it to stdout // it to stdout