Skip to content

Commit 42b3353

Browse files
authored
WIP fix runBackground with -i/--no-server (#4259)
This might have been the cause of a lot of flakiness that seems to have gone away with #4254, as the server exiting caused the `runBackground` calls to exit causing the http servers to exit and fail to pick up requests. Might have been caused by com-lihaoyi/os-lib#324 which made `destroyOnExit` the default for spawned subprocesses. This PR explicitly disables `destroyOnExit` for the subprocesses where `background = true` Covered by a new `integration.invalidation` test that runs under both `server` and `fork`, that previously failed when run under `fork`
1 parent 1adb97d commit 42b3353

File tree

4 files changed

+86
-1
lines changed

4 files changed

+86
-1
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package build
2+
import mill._, javalib._
3+
4+
object foo extends JavaModule{
5+
def runBackgroundLogToConsole: Boolean = false
6+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package foo;
2+
import java.io.RandomAccessFile;
3+
import java.nio.channels.FileChannel;
4+
import java.nio.file.*;
5+
public class Foo {
6+
public static void main(String[] args) throws Exception{
7+
System.out.println("Hello World A!");
8+
RandomAccessFile raf = new RandomAccessFile(args[0], "rw");
9+
System.out.println("Hello World B!");
10+
FileChannel chan = raf.getChannel();
11+
System.out.println("Hello World C!");
12+
chan.lock();
13+
System.out.println("Hello World D!");
14+
while(true){
15+
if (!Files.exists(Paths.get(args[1]))) Thread.sleep(1);
16+
else break;
17+
}
18+
System.out.println("Hello World E!");
19+
}
20+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package mill.integration
2+
3+
import mill.testkit.UtestIntegrationTestSuite
4+
import java.io.RandomAccessFile
5+
import utest.asserts.{RetryInterval, RetryMax}
6+
import scala.concurrent.duration._
7+
import utest._
8+
9+
// Make sure that `runBackground` subprocesses properly outlive the execution
10+
// that created them, and outlive the Mill process whether terminated naturally
11+
// at the end of `--no-server` or terminated explicitly via `shutdown`
12+
object RunBackgroundTests extends UtestIntegrationTestSuite {
13+
implicit val retryMax: RetryMax = RetryMax(5000.millis)
14+
implicit val retryInterval: RetryInterval = RetryInterval(50.millis)
15+
16+
def probeLockAvailable(lock: os.Path): Boolean = {
17+
val raf = new RandomAccessFile(lock.toIO, "rw");
18+
val chan = raf.getChannel();
19+
chan.tryLock() match {
20+
case null => false
21+
case locked =>
22+
locked.release()
23+
true
24+
}
25+
}
26+
27+
val tests: Tests = Tests {
28+
test("simple") - integrationTest { tester =>
29+
import tester._
30+
val lock = os.temp()
31+
val stop = os.temp()
32+
os.remove(stop)
33+
eval(("foo.runBackground", lock, stop))
34+
eventually { !probeLockAvailable(lock) }
35+
if (tester.clientServerMode) eval("shutdown")
36+
continually { !probeLockAvailable(lock) }
37+
os.write(stop, "")
38+
eventually { probeLockAvailable(lock) }
39+
}
40+
test("clean") - integrationTest { tester =>
41+
if (!mill.main.client.Util.isWindows) {
42+
import tester._
43+
val lock = os.temp()
44+
val stop = os.temp()
45+
os.remove(stop)
46+
eval(("foo.runBackground", lock, stop))
47+
eventually {
48+
!probeLockAvailable(lock)
49+
}
50+
51+
eval(("clean", "foo.runBackground"))
52+
eventually {
53+
probeLockAvailable(lock)
54+
}
55+
}
56+
}
57+
}
58+
}

main/util/src/mill/util/Jvm.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -395,7 +395,8 @@ object Jvm extends CoursierSupport {
395395
env = envArgs,
396396
stdin = if (backgroundOutputs.isEmpty) os.Inherit else "",
397397
stdout = backgroundOutputs.map(_._1).getOrElse(os.Inherit),
398-
stderr = backgroundOutputs.map(_._2).getOrElse(os.Inherit)
398+
stderr = backgroundOutputs.map(_._2).getOrElse(os.Inherit),
399+
destroyOnExit = backgroundOutputs.isEmpty
399400
)
400401
}
401402

0 commit comments

Comments
 (0)