mirror of
https://github.com/zed-industries/zed.git
synced 2025-02-03 17:44:30 +00:00
Reap overly long LSP requests with a 2m timeout
Co-authored-by: Julia Risley <julia@zed.dev>
This commit is contained in:
parent
e3a0252b04
commit
7e5735c8f1
1 changed files with 20 additions and 3 deletions
|
@ -4,7 +4,7 @@ pub use lsp_types::*;
|
||||||
|
|
||||||
use anyhow::{anyhow, Context, Result};
|
use anyhow::{anyhow, Context, Result};
|
||||||
use collections::HashMap;
|
use collections::HashMap;
|
||||||
use futures::{channel::oneshot, io::BufWriter, AsyncRead, AsyncWrite};
|
use futures::{channel::oneshot, io::BufWriter, AsyncRead, AsyncWrite, FutureExt};
|
||||||
use gpui::{executor, AsyncAppContext, Task};
|
use gpui::{executor, AsyncAppContext, Task};
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use postage::{barrier, prelude::Stream};
|
use postage::{barrier, prelude::Stream};
|
||||||
|
@ -26,12 +26,14 @@ use std::{
|
||||||
atomic::{AtomicUsize, Ordering::SeqCst},
|
atomic::{AtomicUsize, Ordering::SeqCst},
|
||||||
Arc, Weak,
|
Arc, Weak,
|
||||||
},
|
},
|
||||||
|
time::{Duration, Instant},
|
||||||
};
|
};
|
||||||
use std::{path::Path, process::Stdio};
|
use std::{path::Path, process::Stdio};
|
||||||
use util::{ResultExt, TryFutureExt};
|
use util::{ResultExt, TryFutureExt};
|
||||||
|
|
||||||
const JSON_RPC_VERSION: &str = "2.0";
|
const JSON_RPC_VERSION: &str = "2.0";
|
||||||
const CONTENT_LEN_HEADER: &str = "Content-Length: ";
|
const CONTENT_LEN_HEADER: &str = "Content-Length: ";
|
||||||
|
const LSP_REQUEST_TIMEOUT: Duration = Duration::from_secs(60 * 2);
|
||||||
|
|
||||||
type NotificationHandler = Box<dyn Send + FnMut(Option<usize>, &str, AsyncAppContext)>;
|
type NotificationHandler = Box<dyn Send + FnMut(Option<usize>, &str, AsyncAppContext)>;
|
||||||
type ResponseHandler = Box<dyn Send + FnOnce(Result<String, Error>)>;
|
type ResponseHandler = Box<dyn Send + FnOnce(Result<String, Error>)>;
|
||||||
|
@ -697,7 +699,7 @@ impl LanguageServer {
|
||||||
outbound_tx: &channel::Sender<String>,
|
outbound_tx: &channel::Sender<String>,
|
||||||
executor: &Arc<executor::Background>,
|
executor: &Arc<executor::Background>,
|
||||||
params: T::Params,
|
params: T::Params,
|
||||||
) -> impl 'static + Future<Output = Result<T::Result>>
|
) -> impl 'static + Future<Output = anyhow::Result<T::Result>>
|
||||||
where
|
where
|
||||||
T::Result: 'static + Send,
|
T::Result: 'static + Send,
|
||||||
{
|
{
|
||||||
|
@ -738,10 +740,25 @@ impl LanguageServer {
|
||||||
.try_send(message)
|
.try_send(message)
|
||||||
.context("failed to write to language server's stdin");
|
.context("failed to write to language server's stdin");
|
||||||
|
|
||||||
|
let mut timeout = executor.timer(LSP_REQUEST_TIMEOUT).fuse();
|
||||||
|
let started = Instant::now();
|
||||||
async move {
|
async move {
|
||||||
handle_response?;
|
handle_response?;
|
||||||
send?;
|
send?;
|
||||||
rx.await?
|
|
||||||
|
let method = T::METHOD;
|
||||||
|
futures::select! {
|
||||||
|
response = rx.fuse() => {
|
||||||
|
let elapsed = started.elapsed();
|
||||||
|
log::trace!("Took {elapsed:?} to recieve response to {method:?} id {id}");
|
||||||
|
response?
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = timeout => {
|
||||||
|
log::error!("Cancelled LSP request task for {method:?} id {id} which took over {LSP_REQUEST_TIMEOUT:?}");
|
||||||
|
anyhow::bail!("LSP request timeout");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue