Skip to content

Commit 52bfcd0

Browse files
committed
feat: Fall back to local compilation on server connection/startup failures
Hand-applied port of mozilla#2756 (which is stacked on the unmerged client-side-mode PR upstream) onto the v0.16.0 base: when the client cannot connect to or start the background server and SCCACHE_IGNORE_SERVER_IO_ERROR is set, warn and run the compiler directly instead of failing the compilation. Without this, a storage self-check failure at server startup (e.g. an unreachable or unauthorized cache backend) makes every wrapper invocation exit 2 and fails the build — an optimization must never do that.
1 parent 8da042d commit 52bfcd0

2 files changed

Lines changed: 90 additions & 1 deletion

File tree

src/commands.rs

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -560,6 +560,23 @@ where
560560
}
561561
}
562562

563+
run_compiler_locally(creator, runtime, exe, cmdline, cwd)
564+
}
565+
566+
/// Run the compiler directly, without any caching, and return its exit
567+
/// status. The fallback for invocations the server cannot handle — and,
568+
/// when `SCCACHE_IGNORE_SERVER_IO_ERROR` is set, for a server that cannot
569+
/// be reached or started at all.
570+
fn run_compiler_locally<T>(
571+
mut creator: T,
572+
runtime: &mut Runtime,
573+
exe: &Path,
574+
cmdline: Vec<OsString>,
575+
cwd: &Path,
576+
) -> Result<i32>
577+
where
578+
T: CommandCreatorSync,
579+
{
563580
let mut cmd = creator.new_command_sync(exe);
564581
cmd.args(&cmdline).current_dir(cwd);
565582
if log_enabled!(Trace) {
@@ -807,7 +824,30 @@ pub fn run_command(cmd: Command) -> Result<i32> {
807824
});
808825

809826
let jobserver = Client::new();
810-
let conn = connect_or_start_server(&get_addr(), startup_timeout)?;
827+
let conn = match connect_or_start_server(&get_addr(), startup_timeout) {
828+
Ok(conn) => conn,
829+
Err(error) if ignore_all_server_io_errors() => {
830+
eprintln!(
831+
"sccache: warning: failed to connect to or start server, compiling \
832+
locally instead: {error:#}"
833+
);
834+
let mut runtime = new_client_runtime()?;
835+
let exe = which_in(
836+
Path::new(&exe),
837+
env::var_os("PATH"),
838+
&cwd,
839+
)?;
840+
return run_compiler_locally(
841+
ProcessCommandCreator::new(&jobserver),
842+
&mut runtime,
843+
&exe,
844+
cmdline,
845+
&cwd,
846+
)
847+
.context("failed to execute compiler locally");
848+
}
849+
Err(error) => return Err(error),
850+
};
811851
let mut runtime = new_client_runtime()?;
812852
let res = do_compile(
813853
ProcessCommandCreator::new(&jobserver),

tests/sccache_args.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,55 @@ use std::process::Command;
1414
#[macro_use]
1515
extern crate log;
1616

17+
#[cfg(unix)]
18+
fn command_with_server_start_failure() -> Result<(tempfile::TempDir, Command)> {
19+
let tempdir = tempfile::tempdir()?;
20+
let config = tempdir.path().join("config");
21+
std::fs::write(&config, "")?;
22+
23+
let mut command = Command::new(SCCACHE_BIN.as_os_str());
24+
command
25+
.args(["rustc", "--version"])
26+
.current_dir(tempdir.path())
27+
.env("SCCACHE_CONF", config)
28+
.env("SCCACHE_DIR", tempdir.path().join("cache"))
29+
.env_remove("SCCACHE_IGNORE_SERVER_IO_ERROR")
30+
// Force server start to fail with an overlong unix domain socket.
31+
.env("SCCACHE_SERVER_UDS", "x".repeat(4096));
32+
33+
Ok((tempdir, command))
34+
}
35+
36+
#[cfg(unix)]
37+
#[test]
38+
#[serial]
39+
fn test_server_start_failure_falls_back() -> Result<()> {
40+
let (_tempdir, mut command) = command_with_server_start_failure()?;
41+
42+
command
43+
.env("SCCACHE_IGNORE_SERVER_IO_ERROR", "1")
44+
.assert()
45+
.success()
46+
.stdout(predicate::str::starts_with("rustc "))
47+
.stderr(predicate::str::contains("compiling locally instead"));
48+
49+
Ok(())
50+
}
51+
52+
#[cfg(unix)]
53+
#[test]
54+
#[serial]
55+
fn test_server_start_failure_errors() -> Result<()> {
56+
let (_tempdir, mut command) = command_with_server_start_failure()?;
57+
58+
command
59+
.assert()
60+
.failure()
61+
.stderr(predicate::str::contains("sccache: error"));
62+
63+
Ok(())
64+
}
65+
1766
#[test]
1867
#[serial]
1968
#[cfg(feature = "gcs")]

0 commit comments

Comments
 (0)