@@ -43,6 +43,7 @@ import org.codehaus.groovy.grails.cli.support.PluginPathDiscoverySupport
4343abstract class ForkedGrailsProcess {
4444
4545 public static final String DEBUG_FORK = " grails.debug.fork"
46+ public static final String PARENT_PROCESS_PORT = " grails.fork.parent.process.port"
4647 public static final int DEFAULT_DAEMON_PORT = 8091
4748 public static final String DEFAULT_DEBUG_ARGS = " -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005"
4849
@@ -292,13 +293,13 @@ abstract class ForkedGrailsProcess {
292293 if (daemon && ! connectedToDaemon) {
293294 GrailsConsole . instance. updateStatus(" Running without daemon..." )
294295 }
296+
297+ startParentAvailabilityServer()
298+
295299 String classpathString = getBoostrapClasspath(executionContext)
296- String additionalClasspath = System . getProperty(' GRAILS_ADDITIONAL_CLASSPATH' )
297- if (additionalClasspath) {
298- classpathString = classpathString + File . pathSeparator + additionalClasspath
299- }
300300 List<String > cmd = buildProcessCommand(executionContext, classpathString)
301301
302+
302303 def processBuilder = new ProcessBuilder ()
303304 processBuilder
304305 .directory(executionContext. getBaseDir())
@@ -325,6 +326,21 @@ abstract class ForkedGrailsProcess {
325326 }
326327 }
327328
329+ protected void startParentAvailabilityServer () {
330+ if (System . getProperty(PARENT_PROCESS_PORT )) return
331+
332+ ServerSocket parentAvailabilityServer = new ServerSocket (0 )
333+ def parentPort = parentAvailabilityServer. localPort
334+ System . setProperty(PARENT_PROCESS_PORT , String . valueOf(parentPort))
335+ Runtime . addShutdownHook {
336+ try {
337+ parentAvailabilityServer?. close()
338+ } catch (e) {
339+ // ignore
340+ }
341+ }
342+ }
343+
328344 @CompileStatic
329345 protected void runDaemonCommand (String daemonCmd ) {
330346 def clientSocket = new Socket (" localhost" , daemonPort)
@@ -379,6 +395,8 @@ abstract class ForkedGrailsProcess {
379395 discoverAndSetAgent(executionContext)
380396 }
381397
398+ startParentPortMonitor()
399+
382400 final console = GrailsConsole . instance
383401 console. updateStatus(" Stopping daemon..." )
384402 while (isDaemonRunning()) {
@@ -478,6 +496,11 @@ abstract class ForkedGrailsProcess {
478496
479497 @CompileStatic
480498 protected List<String > buildProcessCommand (ExecutionContext executionContext , String classpathString , boolean isReserve = false , boolean isDaemon = false ) {
499+ String additionalClasspath = System . getProperty(' GRAILS_ADDITIONAL_CLASSPATH' )
500+ if (additionalClasspath) {
501+ classpathString = classpathString + File . pathSeparator + additionalClasspath
502+ }
503+
481504 File tempFile = storeExecutionContext(executionContext)
482505 final javaHomeEnv = System . getenv(" JAVA_HOME" )
483506
@@ -501,7 +524,12 @@ abstract class ForkedGrailsProcess {
501524 cmd. addAll([" -Xmx${ maxMemory} M" . toString(), " -Xms${ minMemory} M" . toString()])
502525 if (! (System . getProperty(" java.version" ) =~ / 1.[89]./ )) {
503526 cmd. add(" -XX:MaxPermSize=${ maxPerm} m" . toString())
504- }
527+ }
528+ def parentPort = System . getProperty(PARENT_PROCESS_PORT )
529+ if (parentPort) {
530+ cmd << " -D${ PARENT_PROCESS_PORT} =${ parentPort} " . toString()
531+ }
532+
505533 cmd. addAll([" -Dgrails.fork.active=true" ,
506534 " -Dgrails.build.execution.context=${ tempFile.canonicalPath} " . toString(), " -cp" , classpathString])
507535
@@ -744,9 +772,46 @@ abstract class ForkedGrailsProcess {
744772
745773 BuildSettingsHolder . settings = buildSettings
746774 configureFork(buildSettings)
775+ startParentPortMonitor()
776+
747777 buildSettings
748778 }
749779
780+ protected void startParentPortMonitor () {
781+ def parentProcessPort = System . getProperty(PARENT_PROCESS_PORT )
782+ if (parentProcessPort) {
783+ Thread . start {
784+ def portInt = parentProcessPort. toInteger()
785+ while (true ) {
786+ sleep(15000 )
787+ if (! isServerRunning(portInt)) {
788+ // parent process killed, so bail out too
789+ GrailsConsole . getInstance(). addStatus(" Parent process shutdown. Exiting..." )
790+ System . exit(1 )
791+ }
792+ }
793+ }
794+ }
795+ }
796+
797+ /**
798+ * @return Whether the server is running
799+ */
800+ boolean isServerRunning (int port ) {
801+ Socket socket = null
802+ try {
803+ socket = new Socket (" localhost" , port)
804+ return socket. isConnected()
805+ } catch (e) {
806+ return false
807+ }
808+ finally {
809+ try {
810+ socket?. close()
811+ } catch (Throwable e) {
812+ }
813+ }
814+ }
750815 protected void configureFork (BuildSettings buildSettings ) {
751816 final runConfig = buildSettings. forkSettings. run
752817 if (runConfig instanceof Map )
0 commit comments