Skip to content

fix(workspace): gracefully handle failing db connections #194

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
4 changes: 4 additions & 0 deletions crates/pg_cli/src/cli_options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ pub struct CliOptions {
#[bpaf(long("use-server"), switch, fallback(false))]
pub use_server: bool,

/// Skip over files containing syntax errors instead of emitting an error diagnostic.
#[bpaf(long("skip-db"), switch, fallback(false))]
pub skip_db: bool,

/// Print additional diagnostics, and some diagnostics show more information. Also, print out what files were processed and which ones were modified.
#[bpaf(long("verbose"), switch, fallback(false))]
pub verbose: bool,
Expand Down
3 changes: 3 additions & 0 deletions crates/pg_cli/src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,10 @@ pub enum PgLspCommand {
Check {
#[bpaf(external(partial_configuration), hide_usage, optional)]
configuration: Option<PartialConfiguration>,

#[bpaf(external, hide_usage)]
cli_options: CliOptions,

/// Use this option when you want to format code piped from `stdin`, and print the output to `stdout`.
///
/// The file doesn't need to exist on disk, what matters is the extension of the file. Based on the extension, we know how to check the code.
Expand Down Expand Up @@ -286,6 +288,7 @@ pub(crate) trait CommandRunner: Sized {
configuration,
vcs_base_path,
gitignore_matches,
skip_db: cli_options.skip_db,
})?;

let execution = self.get_execution(cli_options, console, workspace)?;
Expand Down
6 changes: 6 additions & 0 deletions crates/pg_cli/src/execute/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use crate::reporter::github::{GithubReporter, GithubReporterVisitor};
use crate::reporter::gitlab::{GitLabReporter, GitLabReporterVisitor};
use crate::reporter::junit::{JunitReporter, JunitReporterVisitor};
use crate::reporter::terminal::{ConsoleReporter, ConsoleReporterVisitor};
use crate::reporter::UserHintsPayload;
use crate::{CliDiagnostic, CliSession, DiagnosticsPayload, Reporter};
use pg_diagnostics::{category, Category};
use pg_fs::PgLspPath;
Expand Down Expand Up @@ -242,6 +243,7 @@ pub fn execute_mode(
summary,
evaluated_paths,
diagnostics,
user_hints,
} = traverse(&execution, &mut session, cli_options, paths)?;
let console = session.app.console;
let errors = summary.errors;
Expand All @@ -260,6 +262,7 @@ pub fn execute_mode(
},
execution: execution.clone(),
evaluated_paths,
user_hints_payload: UserHintsPayload { hints: user_hints },
};
reporter.write(&mut ConsoleReporterVisitor(console))?;
}
Expand All @@ -271,6 +274,7 @@ pub fn execute_mode(
diagnostics,
},
execution: execution.clone(),
user_hints: UserHintsPayload { hints: user_hints },
};
reporter.write(&mut GithubReporterVisitor(console))?;
}
Expand All @@ -282,6 +286,7 @@ pub fn execute_mode(
diagnostics,
},
execution: execution.clone(),
user_hints: UserHintsPayload { hints: user_hints },
};
reporter.write(&mut GitLabReporterVisitor::new(
console,
Expand All @@ -297,6 +302,7 @@ pub fn execute_mode(
diagnostics,
},
execution: execution.clone(),
user_hints: UserHintsPayload { hints: user_hints },
};
reporter.write(&mut JunitReporterVisitor::new(console))?;
}
Expand Down
1 change: 1 addition & 0 deletions crates/pg_cli/src/execute/process_file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ pub(crate) enum Message {
diagnostics: Vec<Error>,
skipped_diagnostics: u32,
},
Hint(String),
}

impl Message {
Expand Down
5 changes: 5 additions & 0 deletions crates/pg_cli/src/execute/process_file/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ pub(crate) fn check_with_guard<'ctx>(
let (only, skip) = (Vec::new(), Vec::new());

let max_diagnostics = ctx.remaining_diagnostics.load(Ordering::Relaxed);

let pull_diagnostics_result = workspace_file
.guard()
.pull_diagnostics(
Expand All @@ -41,6 +42,10 @@ pub(crate) fn check_with_guard<'ctx>(
category!("check"),
)?;

if pull_diagnostics_result.skipped_db_checks {
ctx.set_skipped_db_conn(true);
}

let no_diagnostics = pull_diagnostics_result.diagnostics.is_empty()
&& pull_diagnostics_result.skipped_diagnostics == 0;

Expand Down
46 changes: 40 additions & 6 deletions crates/pg_cli/src/execute/traverse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use pg_workspace::workspace::IsPathIgnoredParams;
use pg_workspace::{Workspace, WorkspaceError};
use rustc_hash::FxHashSet;
use std::collections::BTreeSet;
use std::sync::atomic::AtomicU32;
use std::sync::atomic::{AtomicBool, AtomicU32};
use std::sync::RwLock;
use std::{
env::current_dir,
Expand All @@ -33,6 +33,7 @@ pub(crate) struct TraverseResult {
pub(crate) summary: TraversalSummary,
pub(crate) evaluated_paths: BTreeSet<PgLspPath>,
pub(crate) diagnostics: Vec<Error>,
pub(crate) user_hints: Vec<String>,
}

pub(crate) fn traverse(
Expand Down Expand Up @@ -72,6 +73,7 @@ pub(crate) fn traverse(
let unchanged = AtomicUsize::new(0);
let matches = AtomicUsize::new(0);
let skipped = AtomicUsize::new(0);
let skipped_db_conn = AtomicBool::new(false);

let fs = &*session.app.fs;
let workspace = &*session.app.workspace;
Expand All @@ -84,7 +86,7 @@ pub(crate) fn traverse(
.with_diagnostic_level(cli_options.diagnostic_level)
.with_max_diagnostics(max_diagnostics);

let (duration, evaluated_paths, diagnostics) = thread::scope(|s| {
let (duration, evaluated_paths, diagnostics, mut user_hints) = thread::scope(|s| {
let handler = thread::Builder::new()
.name(String::from("pglsp::console"))
.spawn_scoped(s, || printer.run(receiver, recv_files))
Expand All @@ -104,15 +106,16 @@ pub(crate) fn traverse(
changed: &changed,
unchanged: &unchanged,
skipped: &skipped,
skipped_db_conn: &skipped_db_conn,
messages: sender,
remaining_diagnostics: &remaining_diagnostics,
evaluated_paths: RwLock::default(),
},
);
// wait for the main thread to finish
let diagnostics = handler.join().unwrap();
let (diagnostics, user_hints) = handler.join().unwrap();

(elapsed, evaluated_paths, diagnostics)
(elapsed, evaluated_paths, diagnostics, user_hints)
});

let errors = printer.errors();
Expand All @@ -123,6 +126,20 @@ pub(crate) fn traverse(
let skipped = skipped.load(Ordering::Relaxed);
let suggested_fixes_skipped = printer.skipped_fixes();
let diagnostics_not_printed = printer.not_printed_diagnostics();

if duration.as_secs() >= 2 {
user_hints.push(format!(
"The traversal took longer than expected ({}s). Consider using the `--skip-db` option if your Postgres connection is slow.",
duration.as_secs()
));
}

if skipped_db_conn.load(Ordering::Relaxed) {
user_hints.push(format!(
"Skipped all checks requiring database connections.",
));
}

Ok(TraverseResult {
summary: TraversalSummary {
changed,
Expand All @@ -137,6 +154,7 @@ pub(crate) fn traverse(
},
evaluated_paths,
diagnostics,
user_hints,
})
}

Expand Down Expand Up @@ -288,10 +306,15 @@ impl<'ctx> DiagnosticsPrinter<'ctx> {
should_print
}

fn run(&self, receiver: Receiver<Message>, interner: Receiver<PathBuf>) -> Vec<Error> {
fn run(
&self,
receiver: Receiver<Message>,
interner: Receiver<PathBuf>,
) -> (Vec<Error>, Vec<String>) {
let mut paths: FxHashSet<String> = FxHashSet::default();

let mut diagnostics_to_print = vec![];
let mut hints_to_print = vec![];

while let Ok(msg) = receiver.recv() {
match msg {
Expand All @@ -306,6 +329,10 @@ impl<'ctx> DiagnosticsPrinter<'ctx> {
self.errors.fetch_add(1, Ordering::Relaxed);
}

Message::Hint(hint) => {
hints_to_print.push(hint);
}

Message::Error(mut err) => {
let location = err.location();
if self.should_skip_diagnostic(err.severity(), err.tags()) {
Expand Down Expand Up @@ -381,7 +408,8 @@ impl<'ctx> DiagnosticsPrinter<'ctx> {
}
}
}
diagnostics_to_print

(diagnostics_to_print, hints_to_print)
}
}

Expand All @@ -403,6 +431,8 @@ pub(crate) struct TraversalOptions<'ctx, 'app> {
matches: &'ctx AtomicUsize,
/// Shared atomic counter storing the number of skipped files
skipped: &'ctx AtomicUsize,
/// Shared atomic bool tracking whether we used a DB connection
skipped_db_conn: &'ctx AtomicBool,
/// Channel sending messages to the display thread
pub(crate) messages: Sender<Message>,
/// The approximate number of diagnostics the console will print before
Expand Down Expand Up @@ -434,6 +464,10 @@ impl TraversalOptions<'_, '_> {
self.messages.send(msg.into()).ok();
}

pub(crate) fn set_skipped_db_conn(&self, has_skipped: bool) {
self.skipped_db_conn.store(has_skipped, Ordering::Relaxed);
}

pub(crate) fn protected_file(&self, pglsp_path: &PgLspPath) {
self.push_diagnostic(
WorkspaceError::protected_file(pglsp_path.display().to_string()).into(),
Expand Down
15 changes: 15 additions & 0 deletions crates/pg_cli/src/reporter/github.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,18 @@ use pg_console::{markup, Console, ConsoleExt};
use pg_diagnostics::PrintGitHubDiagnostic;
use std::io;

use super::UserHintsPayload;

pub(crate) struct GithubReporter {
pub(crate) diagnostics_payload: DiagnosticsPayload,
pub(crate) execution: Execution,
pub(crate) user_hints: UserHintsPayload,
}

impl Reporter for GithubReporter {
fn write(self, visitor: &mut dyn ReporterVisitor) -> io::Result<()> {
visitor.report_diagnostics(&self.execution, self.diagnostics_payload)?;
visitor.report_user_hints(&self.execution, self.user_hints)?;
Ok(())
}
}
Expand Down Expand Up @@ -42,4 +46,15 @@ impl ReporterVisitor for GithubReporterVisitor<'_> {

Ok(())
}

fn report_user_hints(
&mut self,
_execution: &Execution,
payload: super::UserHintsPayload,
) -> io::Result<()> {
for hint in payload.hints {
self.0.log(markup! {{hint}});
}
Ok(())
}
}
19 changes: 17 additions & 2 deletions crates/pg_cli/src/reporter/gitlab.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,18 @@ use std::{
path::{Path, PathBuf},
};

use super::UserHintsPayload;

pub struct GitLabReporter {
pub execution: Execution,
pub diagnostics: DiagnosticsPayload,
pub(crate) execution: Execution,
pub(crate) diagnostics: DiagnosticsPayload,
pub(crate) user_hints: UserHintsPayload,
}

impl Reporter for GitLabReporter {
fn write(self, visitor: &mut dyn ReporterVisitor) -> std::io::Result<()> {
visitor.report_diagnostics(&self.execution, self.diagnostics)?;
visitor.report_user_hints(&self.execution, self.user_hints)?;
Ok(())
}
}
Expand Down Expand Up @@ -72,6 +76,17 @@ impl ReporterVisitor for GitLabReporterVisitor<'_> {
self.console.log(markup!({ diagnostics }));
Ok(())
}

fn report_user_hints(
&mut self,
_execution: &Execution,
payload: super::UserHintsPayload,
) -> std::io::Result<()> {
for hint in payload.hints {
self.console.log(markup! {{hint}});
}
Ok(())
}
}

struct GitLabDiagnostics<'a>(
Expand Down
17 changes: 17 additions & 0 deletions crates/pg_cli/src/reporter/junit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,20 @@ use quick_junit::{NonSuccessKind, Report, TestCase, TestCaseStatus, TestSuite};
use std::fmt::{Display, Formatter};
use std::io;

use super::UserHintsPayload;

pub(crate) struct JunitReporter {
pub(crate) diagnostics_payload: DiagnosticsPayload,
pub(crate) execution: Execution,
pub(crate) summary: TraversalSummary,
pub(crate) user_hints: UserHintsPayload,
}

impl Reporter for JunitReporter {
fn write(self, visitor: &mut dyn ReporterVisitor) -> io::Result<()> {
visitor.report_summary(&self.execution, self.summary)?;
visitor.report_diagnostics(&self.execution, self.diagnostics_payload)?;
visitor.report_user_hints(&self.execution, self.user_hints)?;
Ok(())
}
}
Expand Down Expand Up @@ -118,4 +122,17 @@ impl ReporterVisitor for JunitReporterVisitor<'_> {

Ok(())
}

fn report_user_hints(
&mut self,
_execution: &Execution,
payload: super::UserHintsPayload,
) -> io::Result<()> {
for hint in payload.hints {
self.1.log(markup! {
{hint}
});
}
Ok(())
}
}
11 changes: 11 additions & 0 deletions crates/pg_cli/src/reporter/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ pub struct DiagnosticsPayload {
pub diagnostic_level: Severity,
}

pub struct UserHintsPayload {
pub hints: Vec<String>,
}

/// A type that holds the result of the traversal
#[derive(Debug, Default, Serialize, Copy, Clone)]
pub struct TraversalSummary {
Expand Down Expand Up @@ -60,4 +64,11 @@ pub trait ReporterVisitor {
execution: &Execution,
payload: DiagnosticsPayload,
) -> io::Result<()>;

/// Writes a diagnostics
fn report_user_hints(
&mut self,
execution: &Execution,
payload: UserHintsPayload,
) -> io::Result<()>;
}
Loading