Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions app/src/App/CLI/Purs.purs
Original file line number Diff line number Diff line change
Expand Up @@ -191,10 +191,17 @@ callCompiler compilerArgs = do
compilerRaceConditionError :: String
compilerRaceConditionError = "Unexpected end of JSON input"

-- | We keep heap exhaustion classified as an unknown error rather than expanding
-- | CompilerFailure because only niche recovery paths need to distinguish it.
isCompilerHeapExhaustion :: CompilerFailure -> Boolean
isCompilerHeapExhaustion = case _ of
UnknownError err -> String.contains (String.Pattern "purs: Heap exhausted") err
_ -> false
Comment thread
thomashoneyman marked this conversation as resolved.

-- | Check if a compiler failure is due to the known race condition bug.
isCompilerRaceCondition :: CompilerFailure -> Boolean
isCompilerRaceCondition = case _ of
UnknownError err -> String.contains (String.Pattern compilerRaceConditionError) err
isCompilerRaceCondition failure = case failure of
UnknownError err -> not (isCompilerHeapExhaustion failure) && String.contains (String.Pattern compilerRaceConditionError) err
_ -> false

-- | Compile PureScript source files with automatic retry for transient errors.
Expand Down
22 changes: 16 additions & 6 deletions app/src/App/Effect/PackageSets.purs
Original file line number Diff line number Diff line change
Expand Up @@ -263,12 +263,22 @@ handle env = case _ of
compileInstalledPackages :: Version -> Run _ (Either CompilerFailure String)
compileInstalledPackages compiler = do
Log.debug "Compiling installed packages..."
Purs.compile
{ globs: [ Path.concat [ Path.basename packagesWorkDir, "**/*.purs" ] ]
, profile: Purs.PackageSetBuild
, version: Just compiler
, cwd: Just env.workdir
}
let
compile = Purs.compile
{ globs: [ Path.concat [ Path.basename packagesWorkDir, "**/*.purs" ] ]
, profile: Purs.PackageSetBuild
, version: Just compiler
, cwd: Just env.workdir
}
result <- compile
case result of
Left err | Purs.isCompilerHeapExhaustion err -> do
Log.warn "Compiler heap exhausted; clearing package-set output and retrying once."
-- Clear the output directory to avoid an incremental build, but leave
-- output-backup alone so it remains available for rollback.
FS.Extra.remove outputWorkDir
compile
_ -> pure result

attemptChanges :: Version -> PackageSet -> ChangeSet -> Run _ (Either CompilerFailure PackageSet)
attemptChanges compiler (PackageSet set) changes = do
Expand Down
9 changes: 9 additions & 0 deletions app/test/App/CLI/Purs.purs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,15 @@ spec = do
let err = UnknownError "Some prefix text\nJSON: Unexpected end of JSON input\nSome suffix"
Purs.isCompilerRaceCondition err `Assertions.shouldEqual` true

Spec.it "Does not detect race condition for heap exhaustion with empty JSON output" do
let
err = UnknownError $ String.joinWith "\n"
[ "purs: Heap exhausted;"
, "purs: Current maximum heap size is 3221225472 bytes (3072 MB)."
, "JSON: Unexpected end of JSON input"
]
Purs.isCompilerRaceCondition err `Assertions.shouldEqual` false

Spec.it "Does not detect race condition for normal UnknownError" do
let err = UnknownError "Some other compiler error message"
Purs.isCompilerRaceCondition err `Assertions.shouldEqual` false
Expand Down
Loading