mirror of https://github.com/sbt/sbt.git
[2.x] fix: Widen IOException catch in organicTask to cover result serialization (#9050)
**Problem** When a file referenced during cache serialization is deleted between task execution and cache storage, sbt crashes with an uncaught NoSuchFileException. The IOException catch added in #8699 only wraps store.put(), but Converter.toJsonUnsafe(result) and mkInput() also call hashedVirtualFileRefToStr which calls Files.readAttributes — and these are outside the try-catch. **Solution** Move the try/catch IOException to wrap the entire post-action cache storage section, so NoSuchFileException from result serialization or cache key computation is caught and handled gracefully (skip caching, return result). Fixes #9044 Co-authored-by: bittoby <218712309+bittoby@users.noreply.github.co>
This commit is contained in:
parent
d765ba263a
commit
e0bdb531f7
|
|
@ -82,40 +82,40 @@ object ActionCache:
|
||||||
case e: Exception =>
|
case e: Exception =>
|
||||||
cacheEventLog.append(ActionCacheEvent.Error)
|
cacheEventLog.append(ActionCacheEvent.Error)
|
||||||
throw e
|
throw e
|
||||||
val json = Converter.toJsonUnsafe(result)
|
try
|
||||||
val normalizedOutputDir = outputDirectory.toAbsolutePath.normalize()
|
val json = Converter.toJsonUnsafe(result)
|
||||||
val uncacheableOutputs =
|
val normalizedOutputDir = outputDirectory.toAbsolutePath.normalize()
|
||||||
outputs.filter(f =>
|
val uncacheableOutputs =
|
||||||
f match
|
outputs.filter(f =>
|
||||||
case vf if vf.id.endsWith(ActionCache.dirZipExt) =>
|
f match
|
||||||
false
|
case vf if vf.id.endsWith(ActionCache.dirZipExt) =>
|
||||||
case _ =>
|
false
|
||||||
val outputPath = fileConverter.toPath(f).toAbsolutePath.normalize()
|
case _ =>
|
||||||
!outputPath.startsWith(normalizedOutputDir)
|
val outputPath = fileConverter.toPath(f).toAbsolutePath.normalize()
|
||||||
)
|
!outputPath.startsWith(normalizedOutputDir)
|
||||||
if uncacheableOutputs.nonEmpty then
|
)
|
||||||
cacheEventLog.append(ActionCacheEvent.Error)
|
if uncacheableOutputs.nonEmpty then
|
||||||
logger.error(
|
cacheEventLog.append(ActionCacheEvent.Error)
|
||||||
s"Cannot cache task because its output files are outside the output directory: \n" +
|
logger.error(
|
||||||
uncacheableOutputs.mkString(" - ", "\n - ", "")
|
s"Cannot cache task because its output files are outside the output directory: \n" +
|
||||||
)
|
uncacheableOutputs.mkString(" - ", "\n - ", "")
|
||||||
result
|
)
|
||||||
else
|
result
|
||||||
cacheEventLog.append(ActionCacheEvent.OnsiteTask)
|
else
|
||||||
val (input, valuePath) = mkInput(key, codeContentHash, extraHash, config.cacheVersion)
|
cacheEventLog.append(ActionCacheEvent.OnsiteTask)
|
||||||
val valueFile = StringVirtualFile1(valuePath, CompactPrinter(json))
|
val (input, valuePath) = mkInput(key, codeContentHash, extraHash, config.cacheVersion)
|
||||||
val newOutputs = Vector(valueFile) ++ outputs.toVector
|
val valueFile = StringVirtualFile1(valuePath, CompactPrinter(json))
|
||||||
try
|
val newOutputs = Vector(valueFile) ++ outputs.toVector
|
||||||
store.put(UpdateActionResultRequest(input, newOutputs, exitCode = 0)) match
|
store.put(UpdateActionResultRequest(input, newOutputs, exitCode = 0)) match
|
||||||
case Right(cachedResult) =>
|
case Right(cachedResult) =>
|
||||||
store.syncBlobs(cachedResult.outputFiles, outputDirectory)
|
store.syncBlobs(cachedResult.outputFiles, outputDirectory)
|
||||||
result
|
result
|
||||||
case Left(e) => throw e
|
case Left(e) => throw e
|
||||||
catch
|
catch
|
||||||
case e: IOException =>
|
case e: IOException =>
|
||||||
logger.debug(s"Skipping cache storage due to error: ${e.getMessage}")
|
logger.debug(s"Skipping cache storage due to error: ${e.getMessage}")
|
||||||
cacheEventLog.append(ActionCacheEvent.Error)
|
cacheEventLog.append(ActionCacheEvent.Error)
|
||||||
result
|
result
|
||||||
|
|
||||||
// Single cache lookup - use exitCode to distinguish success from failure
|
// Single cache lookup - use exitCode to distinguish success from failure
|
||||||
getWithFailure(key, codeContentHash, extraHash, tags, config) match
|
getWithFailure(key, codeContentHash, extraHash, tags, config) match
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue