def __enter__(self): now_us = monotonic_time_nanos() / 1000 self._add_trace_event( 'buck-launcher', self.name, _TraceEventPhases.BEGIN, self.pid, 1, now_us, self.args)
def __exit__(self, x_type, x_value, x_traceback): now_us = monotonic_time_nanos() / 1000 self._add_trace_event( 'buck-launcher', self.name, _TraceEventPhases.END, self.pid, 1, now_us, self.args)
def launch_buckd(self, buck_version_uid=None): with Tracing('BuckRepo.launch_buckd'): self._setup_watchman_watch() if buck_version_uid is None: buck_version_uid = self._get_buck_version_uid() # Override self._tmp_dir to a long lived directory. buckd_tmp_dir = self._buck_project.create_buckd_tmp_dir() ngserver_output_path = os.path.join(buckd_tmp_dir, 'ngserver-out') ''' Use SoftRefLRUPolicyMSPerMB for immediate GC of javac output. Set timeout to 60s (longer than the biggest GC pause seen for a 2GB heap) and GC target to 15s. This means that the GC has to miss its target by 100% or many 500ms heartbeats must be missed before a client disconnection occurs. Specify port 0 to allow Nailgun to find an available port, then parse the port number out of the first log entry. ''' command = ["buckd"] command.extend(self._get_java_args(buck_version_uid)) command.append("-Dbuck.buckd_launch_time_nanos={0}".format( monotonic_time_nanos())) command.append( "-XX:MaxGCPauseMillis={0}".format(GC_MAX_PAUSE_TARGET)) command.append("-XX:SoftRefLRUPolicyMSPerMB=0") command.append("-Djava.io.tmpdir={0}".format(buckd_tmp_dir)) command.append( "-Dcom.martiansoftware.nailgun.NGServer.outputPath={0}".format( ngserver_output_path)) command.append( "com.facebook.buck.cli.bootstrapper.ClassLoaderBootstrapper") command.append("com.martiansoftware.nailgun.NGServer") command.append("localhost:0") command.append("{0}".format(BUCKD_CLIENT_TIMEOUT_MILLIS)) ''' Change the process group of the child buckd process so that when this script is interrupted, it does not kill buckd. ''' def preexec_func(): # Close any open file descriptors to further separate buckd from its # invoking context (e.g. otherwise we'd hang when running things like # `ssh localhost buck clean`). # N.B. preexec_func is POSIX-only, and any reasonable # POSIX system has a /dev/null os.setpgrp() dev_null_fd = os.open("/dev/null", os.O_RDWR) os.dup2(dev_null_fd, 0) os.dup2(dev_null_fd, 1) os.dup2(dev_null_fd, 2) os.close(dev_null_fd) process = subprocess.Popen(command, executable=which("java"), cwd=self._buck_project.root, close_fds=True, preexec_fn=preexec_func, env=self._environ_for_buck()) buckd_port = None for i in range(100): if buckd_port: break try: with open(ngserver_output_path) as f: for line in f: match = BUCKD_LOG_FILE_PATTERN.match(line) if match: buckd_port = match.group(1) break except IOError as e: pass finally: time.sleep(0.1) else: print( "nailgun server did not respond after 10s. Aborting buckd.", file=sys.stderr) return self._buck_project.save_buckd_port(buckd_port) self._buck_project.save_buckd_version(buck_version_uid) self._buck_project.update_buckd_run_count(0)
def launch_buckd(self, buck_version_uid=None): with Tracing('BuckRepo.launch_buckd'): self._setup_watchman_watch() if buck_version_uid is None: buck_version_uid = self._get_buck_version_uid() # Override self._tmp_dir to a long lived directory. buckd_tmp_dir = self._buck_project.create_buckd_tmp_dir() ngserver_output_path = os.path.join(buckd_tmp_dir, 'ngserver-out') ''' Use SoftRefLRUPolicyMSPerMB for immediate GC of javac output. Set timeout to 60s (longer than the biggest GC pause seen for a 2GB heap) and GC target to 15s. This means that the GC has to miss its target by 100% or many 500ms heartbeats must be missed before a client disconnection occurs. Specify port 0 to allow Nailgun to find an available port, then parse the port number out of the first log entry. ''' command = ["buckd"] command.extend(self._get_java_args(buck_version_uid)) command.append("-Dbuck.buckd_launch_time_nanos={0}".format(monotonic_time_nanos())) command.append("-XX:MaxGCPauseMillis={0}".format(GC_MAX_PAUSE_TARGET)) command.append("-XX:SoftRefLRUPolicyMSPerMB=0") command.append("-Djava.io.tmpdir={0}".format(buckd_tmp_dir)) command.append("-Dcom.martiansoftware.nailgun.NGServer.outputPath={0}".format( ngserver_output_path)) command.append("com.facebook.buck.cli.bootstrapper.ClassLoaderBootstrapper") command.append("com.martiansoftware.nailgun.NGServer") command.append("localhost:0") command.append("{0}".format(BUCKD_CLIENT_TIMEOUT_MILLIS)) ''' Change the process group of the child buckd process so that when this script is interrupted, it does not kill buckd. ''' def preexec_func(): # Close any open file descriptors to further separate buckd from its # invoking context (e.g. otherwise we'd hang when running things like # `ssh localhost buck clean`). # N.B. preexec_func is POSIX-only, and any reasonable # POSIX system has a /dev/null os.setpgrp() dev_null_fd = os.open("/dev/null", os.O_RDWR) os.dup2(dev_null_fd, 0) os.dup2(dev_null_fd, 1) os.dup2(dev_null_fd, 2) os.close(dev_null_fd) process = subprocess.Popen( command, executable=which("java"), cwd=self._buck_project.root, close_fds=True, preexec_fn=preexec_func, env=self._environ_for_buck()) buckd_port = None for i in range(100): if buckd_port: break try: with open(ngserver_output_path) as f: for line in f: match = BUCKD_LOG_FILE_PATTERN.match(line) if match: buckd_port = match.group(1) break except IOError as e: pass finally: time.sleep(0.1) else: print( "nailgun server did not respond after 10s. Aborting buckd.", file=sys.stderr) return 1 self._buck_project.save_buckd_port(buckd_port) self._buck_project.save_buckd_version(buck_version_uid) self._buck_project.update_buckd_run_count(0) returncode = process.poll() # If the process hasn't exited yet, everything is working as expected if returncode is None: return 0 return returncode
def launch_buckd(self, java11_test_mode, buck_version_uid=None): with Tracing("BuckTool.launch_buckd"): setup_watchman_watch() if buck_version_uid is None: buck_version_uid = self._get_buck_version_uid() # Override self._tmp_dir to a long lived directory. buckd_tmp_dir = self._buck_project.create_buckd_tmp_dir() ngserver_output_path = os.path.join(buckd_tmp_dir, "ngserver-out") """ Use SoftRefLRUPolicyMSPerMB for immediate GC of javac output. Set timeout to 60s (longer than the biggest GC pause seen for a 2GB heap) and GC target to 15s. This means that the GC has to miss its target by 100% or many 500ms heartbeats must be missed before a client disconnection occurs. Specify port 0 to allow Nailgun to find an available port, then parse the port number out of the first log entry. """ command = ["buckd"] extra_default_options = [ "-Dbuck.buckd_launch_time_nanos={0}".format( monotonic_time_nanos()), "-Dfile.encoding=UTF-8", "-XX:MaxGCPauseMillis={0}".format(GC_MAX_PAUSE_TARGET), "-XX:SoftRefLRUPolicyMSPerMB=0", # Stop Java waking up every 50ms to collect thread # statistics; doing it once every five seconds is much # saner for a long-lived daemon. "-XX:PerfDataSamplingInterval=5000", # Do not touch most signals "-Xrs", # Likewise, waking up once per second just in case # there's some rebalancing to be done is silly. "-XX:+UnlockDiagnosticVMOptions", "-XX:GuaranteedSafepointInterval=5000", "-Djava.io.tmpdir={0}".format(buckd_tmp_dir), "-Dcom.facebook.nailgun.NGServer.outputPath={0}".format( ngserver_output_path), "-XX:+UseG1GC", "-XX:MaxHeapFreeRatio=40", ] command.extend( self._get_java_args(buck_version_uid, java11_test_mode, extra_default_options)) command.append( "com.facebook.buck.cli.bootstrapper.ClassLoaderBootstrapper") command.append("com.facebook.buck.cli.Main$DaemonBootstrap") command.append(self._buck_project.get_buckd_transport_address()) command.append("{0}".format(BUCKD_CLIENT_TIMEOUT_MILLIS)) buckd_transport_file_path = ( self._buck_project.get_buckd_transport_file_path()) if os.name == "nt": # https://msdn.microsoft.com/en-us/library/windows/desktop/ms684863.aspx#DETACHED_PROCESS DETACHED_PROCESS = 0x00000008 creationflags = DETACHED_PROCESS # do not redirect output for Windows as it deadlocks stdin = None stdout = None stderr = None close_fds = True else: """ Change the process group of the child buckd process so that when this script is interrupted, it does not kill buckd. """ creationflags = 0 stdin = open(os.devnull, mode="r") stdout = open(self._buck_project.get_buckd_stdout(), mode="w+b", buffering=0) stderr = open(self._buck_project.get_buckd_stderr(), mode="w+b", buffering=0) close_fds = False process = subprocess.Popen( command, executable=get_java_path(), cwd=self._buck_project.root, env=self._environ_for_buck(), creationflags=creationflags, close_fds=close_fds, stdin=stdin, stdout=stdout, stderr=stderr, ) self._buck_project.save_buckd_version(buck_version_uid) # Give Java some time to create the listening socket. wait_seconds = 0.01 repetitions = int(BUCKD_STARTUP_TIMEOUT_MILLIS / 1000.0 / wait_seconds) for i in range(repetitions): if transport_exists(buckd_transport_file_path): break time.sleep(wait_seconds) if not transport_exists(buckd_transport_file_path): return False returncode = process.poll() # If the process has exited then daemon failed to start if returncode is not None: return False # Save pid of running daemon self._buck_project.save_buckd_pid(process.pid) return True
def launch_buckd(self): with Tracing('BuckRepo.launch_buckd'): self._setup_watchman_watch() self._buck_project.create_buckd_tmp_dir() # Override self._tmp_dir to a long lived directory. buckd_tmp_dir = self._buck_project.buckd_tmp_dir ''' Use SoftRefLRUPolicyMSPerMB for immediate GC of javac output. Set timeout to 60s (longer than the biggest GC pause seen for a 2GB heap) and GC target to 15s. This means that the GC has to miss its target by 100% or many 500ms heartbeats must be missed before a client disconnection occurs. Specify port 0 to allow Nailgun to find an available port, then parse the port number out of the first log entry. ''' command = ["java"] command.extend(self._get_java_args(self._buck_version_uid)) command.append("-Dbuck.buckd_launch_time_nanos={0}".format(monotonic_time_nanos())) command.append("-Dbuck.buckd_watcher=Watchman") command.append("-XX:MaxGCPauseMillis={0}".format(GC_MAX_PAUSE_TARGET)) command.append("-XX:SoftRefLRUPolicyMSPerMB=0") command.append("-Djava.io.tmpdir={0}".format(buckd_tmp_dir)) command.append("-classpath") command.append(self._get_java_classpath()) command.append("com.martiansoftware.nailgun.NGServer") command.append("localhost:0") command.append("{0}".format(BUCKD_CLIENT_TIMEOUT_MILLIS)) ''' We want to launch the buckd process in such a way that it finds the terminal as a tty while being able to read its output. We also want to shut up any nailgun output. If we simply redirect stdout/stderr to a file, the super console no longer works on subsequent invocations of buck. So use a pseudo-terminal to interact with it. ''' master, slave = pty.openpty() ''' Change the process group of the child buckd process so that when this script is interrupted, it does not kill buckd. ''' def preexec_func(): os.setpgrp() process = subprocess.Popen( command, cwd=self._buck_project.root, stdout=slave, stderr=slave, preexec_fn=preexec_func) stdout = os.fdopen(master) for i in range(100): line = stdout.readline().strip() match = BUCKD_LOG_FILE_PATTERN.match(line) if match: buckd_port = match.group(1) break time.sleep(0.1) else: print( "nailgun server did not respond after 10s. Aborting buckd.", file=sys.stderr) return self._buck_project.save_buckd_port(buckd_port) self._buck_project.save_buckd_version(self._buck_version_uid) self._buck_project.update_buckd_run_count(0)
def launch_buckd(self, buck_version_uid=None): with Tracing("BuckRepo.launch_buckd"): self._setup_watchman_watch() if buck_version_uid is None: buck_version_uid = self._get_buck_version_uid() # Override self._tmp_dir to a long lived directory. buckd_tmp_dir = self._buck_project.create_buckd_tmp_dir() ngserver_output_path = os.path.join(buckd_tmp_dir, "ngserver-out") """ Use SoftRefLRUPolicyMSPerMB for immediate GC of javac output. Set timeout to 60s (longer than the biggest GC pause seen for a 2GB heap) and GC target to 15s. This means that the GC has to miss its target by 100% or many 500ms heartbeats must be missed before a client disconnection occurs. Specify port 0 to allow Nailgun to find an available port, then parse the port number out of the first log entry. """ command = ["buckd"] extra_default_options = [ "-Dbuck.buckd_launch_time_nanos={0}".format(monotonic_time_nanos()), "-XX:MaxGCPauseMillis={0}".format(GC_MAX_PAUSE_TARGET), "-XX:SoftRefLRUPolicyMSPerMB=0", # Stop Java waking up every 50ms to collect thread # statistics; doing it once every five seconds is much # saner for a long-lived daemon. "-XX:PerfDataSamplingInterval=5000", # Likewise, waking up once per second just in case # there's some rebalancing to be done is silly. "-XX:+UnlockDiagnosticVMOptions", "-XX:GuaranteedSafepointInterval=5000", "-Djava.io.tmpdir={0}".format(buckd_tmp_dir), "-Dcom.martiansoftware.nailgun.NGServer.outputPath={0}".format(ngserver_output_path), ] if is_java8(): extra_default_options.extend(["-XX:+UseG1GC", "-XX:MaxHeapFreeRatio=40"]) command.extend(self._get_java_args(buck_version_uid, extra_default_options)) command.append("com.facebook.buck.cli.bootstrapper.ClassLoaderBootstrapper") command.append("com.martiansoftware.nailgun.NGServer") command.append("local:.buckd/sock") command.append("{0}".format(BUCKD_CLIENT_TIMEOUT_MILLIS)) """ Change the process group of the child buckd process so that when this script is interrupted, it does not kill buckd. """ def preexec_func(): # Close any open file descriptors to further separate buckd from its # invoking context (e.g. otherwise we'd hang when running things like # `ssh localhost buck clean`). # N.B. preexec_func is POSIX-only, and any reasonable # POSIX system has a /dev/null os.setpgrp() dev_null_fd = os.open("/dev/null", os.O_RDWR) os.dup2(dev_null_fd, 0) os.dup2(dev_null_fd, 1) os.dup2(dev_null_fd, 2) os.close(dev_null_fd) buck_socket_path = self._buck_project.get_buckd_socket_path() # Make sure the Unix domain socket doesn't exist before this call. try: os.unlink(buck_socket_path) except OSError as e: if e.errno == errno.ENOENT: # Socket didn't previously exist. pass else: raise e process = subprocess.Popen( command, executable=which("java"), cwd=self._buck_project.root, close_fds=True, preexec_fn=preexec_func, env=self._environ_for_buck(), ) self._buck_project.save_buckd_version(buck_version_uid) self._buck_project.update_buckd_run_count(0) # Give Java some time to create the listening socket. for i in range(0, 100): if not os.path.exists(buck_socket_path): time.sleep(0.01) returncode = process.poll() # If the process hasn't exited yet, everything is working as expected if returncode is None: return 0 return returncode
def launch_buckd(self, buck_version_uid=None): with Tracing('BuckTool.launch_buckd'): setup_watchman_watch() if buck_version_uid is None: buck_version_uid = self._get_buck_version_uid() # Override self._tmp_dir to a long lived directory. buckd_tmp_dir = self._buck_project.create_buckd_tmp_dir() ngserver_output_path = os.path.join(buckd_tmp_dir, 'ngserver-out') ''' Use SoftRefLRUPolicyMSPerMB for immediate GC of javac output. Set timeout to 60s (longer than the biggest GC pause seen for a 2GB heap) and GC target to 15s. This means that the GC has to miss its target by 100% or many 500ms heartbeats must be missed before a client disconnection occurs. Specify port 0 to allow Nailgun to find an available port, then parse the port number out of the first log entry. ''' command = ["buckd"] extra_default_options = [ "-Dbuck.buckd_launch_time_nanos={0}".format( monotonic_time_nanos()), "-XX:MaxGCPauseMillis={0}".format(GC_MAX_PAUSE_TARGET), "-XX:SoftRefLRUPolicyMSPerMB=0", # Stop Java waking up every 50ms to collect thread # statistics; doing it once every five seconds is much # saner for a long-lived daemon. "-XX:PerfDataSamplingInterval=5000", # Do not touch most signals "-Xrs", # Likewise, waking up once per second just in case # there's some rebalancing to be done is silly. "-XX:+UnlockDiagnosticVMOptions", "-XX:GuaranteedSafepointInterval=5000", "-Djava.io.tmpdir={0}".format(buckd_tmp_dir), "-Dcom.martiansoftware.nailgun.NGServer.outputPath={0}".format( ngserver_output_path), "-XX:+UseG1GC", "-XX:MaxHeapFreeRatio=40", ] command.extend( self._get_java_args(buck_version_uid, extra_default_options)) command.append( "com.facebook.buck.cli.bootstrapper.ClassLoaderBootstrapper") command.append("com.facebook.buck.cli.Main$DaemonBootstrap") command.append(self._buck_project.get_buckd_transport_address()) command.append("{0}".format(BUCKD_CLIENT_TIMEOUT_MILLIS)) buckd_transport_file_path = self._buck_project.get_buckd_transport_file_path( ) if os.name == 'nt': preexec_fn = None # https://msdn.microsoft.com/en-us/library/windows/desktop/ms684863.aspx#DETACHED_PROCESS DETACHED_PROCESS = 0x00000008 creationflags = DETACHED_PROCESS else: # Make sure the Unix domain socket doesn't exist before this call. try: os.unlink(buckd_transport_file_path) except OSError as e: if e.errno == errno.ENOENT: # Socket didn't previously exist. pass else: raise e ''' Change the process group of the child buckd process so that when this script is interrupted, it does not kill buckd. ''' def preexec_fn(): # Close any open file descriptors to further separate buckd from its # invoking context (e.g. otherwise we'd hang when running things like # `ssh localhost buck clean`). dev_null_fd = os.open("/dev/null", os.O_RDWR) os.dup2(dev_null_fd, 0) os.dup2(dev_null_fd, 1) os.dup2(dev_null_fd, 2) os.close(dev_null_fd) creationflags = 0 process = subprocess.Popen(command, executable=which("java"), cwd=self._buck_project.root, close_fds=True, preexec_fn=preexec_fn, env=self._environ_for_buck(), creationflags=creationflags) self._buck_project.save_buckd_version(buck_version_uid) # Give Java some time to create the listening socket. for i in range(0, 300): if not transport_exists(buckd_transport_file_path): time.sleep(0.01) returncode = process.poll() # If the process hasn't exited yet, everything is working as expected if returncode is None: return 0 return returncode
def launch_buckd(self, buck_version_uid=None): with Tracing('BuckTool.launch_buckd'): setup_watchman_watch() if buck_version_uid is None: buck_version_uid = self._get_buck_version_uid() # Override self._tmp_dir to a long lived directory. buckd_tmp_dir = self._buck_project.create_buckd_tmp_dir() ngserver_output_path = os.path.join(buckd_tmp_dir, 'ngserver-out') """ Use SoftRefLRUPolicyMSPerMB for immediate GC of javac output. Set timeout to 60s (longer than the biggest GC pause seen for a 2GB heap) and GC target to 15s. This means that the GC has to miss its target by 100% or many 500ms heartbeats must be missed before a client disconnection occurs. Specify port 0 to allow Nailgun to find an available port, then parse the port number out of the first log entry. """ command = ["buckd"] extra_default_options = [ "-Dbuck.buckd_launch_time_nanos={0}".format(monotonic_time_nanos()), "-Dfile.encoding=UTF-8", "-XX:MaxGCPauseMillis={0}".format(GC_MAX_PAUSE_TARGET), "-XX:SoftRefLRUPolicyMSPerMB=0", # Stop Java waking up every 50ms to collect thread # statistics; doing it once every five seconds is much # saner for a long-lived daemon. "-XX:PerfDataSamplingInterval=5000", # Do not touch most signals "-Xrs", # Likewise, waking up once per second just in case # there's some rebalancing to be done is silly. "-XX:+UnlockDiagnosticVMOptions", "-XX:GuaranteedSafepointInterval=5000", "-Djava.io.tmpdir={0}".format(buckd_tmp_dir), "-Dcom.martiansoftware.nailgun.NGServer.outputPath={0}".format( ngserver_output_path), "-XX:+UseG1GC", "-XX:MaxHeapFreeRatio=40", ] command.extend(self._get_java_args(buck_version_uid, extra_default_options)) command.append("com.facebook.buck.cli.bootstrapper.ClassLoaderBootstrapper") command.append("com.facebook.buck.cli.Main$DaemonBootstrap") command.append(self._buck_project.get_buckd_transport_address()) command.append("{0}".format(BUCKD_CLIENT_TIMEOUT_MILLIS)) buckd_transport_file_path = self._buck_project.get_buckd_transport_file_path() if os.name == 'nt': preexec_fn = None # https://msdn.microsoft.com/en-us/library/windows/desktop/ms684863.aspx#DETACHED_PROCESS DETACHED_PROCESS = 0x00000008 creationflags = DETACHED_PROCESS else: """ Change the process group of the child buckd process so that when this script is interrupted, it does not kill buckd. """ def preexec_fn(): # Close any open file descriptors to further separate buckd from its # invoking context (e.g. otherwise we'd hang when running things like # `ssh localhost buck clean`). dev_null_fd = os.open("/dev/null", os.O_RDWR) os.dup2(dev_null_fd, 0) os.dup2(dev_null_fd, 1) os.dup2(dev_null_fd, 2) os.close(dev_null_fd) creationflags = 0 process = subprocess.Popen( command, executable=which("java"), cwd=self._buck_project.root, close_fds=True, preexec_fn=preexec_fn, env=self._environ_for_buck(), creationflags=creationflags) self._buck_project.save_buckd_version(buck_version_uid) # Give Java some time to create the listening socket. wait_seconds = 0.01 repetitions = int(BUCKD_STARTUP_TIMEOUT_MILLIS / 1000.0 / wait_seconds) for i in range(repetitions): if transport_exists(buckd_transport_file_path): break time.sleep(wait_seconds) if not transport_exists(buckd_transport_file_path): return False returncode = process.poll() # If the process hasn't exited yet, everything is working as expected if returncode is None: return True return False
def launch_buckd(self, java_path, jvm_args, buck_version_uid=None): with Tracing("BuckTool.launch_buckd"): setup_watchman_watch() if buck_version_uid is None: buck_version_uid = self._get_buck_version_uid() # Override self._tmp_dir to a long lived directory. buckd_tmp_dir = self._buck_project.create_buckd_tmp_dir() ngserver_output_path = os.path.join(buckd_tmp_dir, "ngserver-out") """ Use SoftRefLRUPolicyMSPerMB for immediate GC of javac output. Set timeout to 60s (longer than the biggest GC pause seen for a 2GB heap) and GC target to 15s. This means that the GC has to miss its target by 100% or many 500ms heartbeats must be missed before a client disconnection occurs. Specify port 0 to allow Nailgun to find an available port, then parse the port number out of the first log entry. """ command = ["buckd"] extra_default_options = [ "-Dbuck.buckd_launch_time_nanos={0}".format(monotonic_time_nanos()), "-Dfile.encoding=UTF-8", "-XX:MaxGCPauseMillis={0}".format(GC_MAX_PAUSE_TARGET), "-XX:SoftRefLRUPolicyMSPerMB=0", # Stop Java waking up every 50ms to collect thread # statistics; doing it once every five seconds is much # saner for a long-lived daemon. "-XX:PerfDataSamplingInterval=5000", # Do not touch most signals "-Xrs", # Likewise, waking up once per second just in case # there's some rebalancing to be done is silly. "-XX:+UnlockDiagnosticVMOptions", "-XX:GuaranteedSafepointInterval=5000", "-Djava.io.tmpdir={0}".format(buckd_tmp_dir), "-Dcom.facebook.nailgun.NGServer.outputPath={0}".format( ngserver_output_path ), "-XX:+UseG1GC", "-XX:MaxHeapFreeRatio=40", ] command.extend(extra_default_options) command.extend(jvm_args) command.append("com.facebook.buck.cli.bootstrapper.ClassLoaderBootstrapper") command.append("com.facebook.buck.cli.BuckDaemon") command.append(self._buck_project.get_buckd_transport_address()) command.append("{0}".format(BUCKD_CLIENT_TIMEOUT_MILLIS)) buckd_transport_file_path = ( self._buck_project.get_buckd_transport_file_path() ) if os.name == "nt": # https://msdn.microsoft.com/en-us/library/windows/desktop/ms684863.aspx#DETACHED_PROCESS DETACHED_PROCESS = 0x00000008 creationflags = DETACHED_PROCESS # do not redirect output for Windows as it deadlocks stdin = None stdout = None stderr = None close_fds = True else: """ Change the process group of the child buckd process so that when this script is interrupted, it does not kill buckd. """ creationflags = 0 stdin = open(os.devnull, mode="r") stdout = open( self._buck_project.get_buckd_stdout(), mode="w+b", buffering=0 ) stderr = open( self._buck_project.get_buckd_stderr(), mode="w+b", buffering=0 ) close_fds = False process = subprocess.Popen( command, executable=java_path, cwd=self._buck_project.root, env=self._environ_for_buck(), creationflags=creationflags, close_fds=close_fds, stdin=stdin, stdout=stdout, stderr=stderr, ) self._buck_project.save_buckd_version(buck_version_uid) self._buck_project.save_buckd_jvm_args( self._get_java_args(buck_version_uid) ) # Give Java some time to create the listening socket. wait_seconds = 0.01 repetitions = int(BUCKD_STARTUP_TIMEOUT_MILLIS / 1000.0 / wait_seconds) for i in range(repetitions): if transport_exists(buckd_transport_file_path): break time.sleep(wait_seconds) if not transport_exists(buckd_transport_file_path): return False returncode = process.poll() # If the process has exited then daemon failed to start if returncode is not None: return False # Save pid of running daemon self._buck_project.save_buckd_pid(process.pid) return True
def launch_buckd(self, buck_version_uid=None): with Tracing('BuckRepo.launch_buckd'): self._setup_watchman_watch() if buck_version_uid is None: buck_version_uid = self._get_buck_version_uid() # Override self._tmp_dir to a long lived directory. buckd_tmp_dir = self._buck_project.create_buckd_tmp_dir() ngserver_output_path = os.path.join(buckd_tmp_dir, 'ngserver-out') ''' Use SoftRefLRUPolicyMSPerMB for immediate GC of javac output. Set timeout to 60s (longer than the biggest GC pause seen for a 2GB heap) and GC target to 15s. This means that the GC has to miss its target by 100% or many 500ms heartbeats must be missed before a client disconnection occurs. Specify port 0 to allow Nailgun to find an available port, then parse the port number out of the first log entry. ''' command = [which("java")] command.extend(self._get_java_args(buck_version_uid)) command.append("-Dbuck.buckd_launch_time_nanos={0}".format(monotonic_time_nanos())) command.append("-Dbuck.buckd_watcher=Watchman") command.append("-XX:MaxGCPauseMillis={0}".format(GC_MAX_PAUSE_TARGET)) command.append("-XX:SoftRefLRUPolicyMSPerMB=0") command.append("-Djava.io.tmpdir={0}".format(buckd_tmp_dir)) command.append("-Dcom.martiansoftware.nailgun.NGServer.outputPath={0}".format( ngserver_output_path)) command.append("-classpath") command.append(self._get_bootstrap_classpath()) command.append("com.facebook.buck.cli.bootstrapper.ClassLoaderBootstrapper") command.append(self._get_java_classpath()) command.append("com.martiansoftware.nailgun.NGServer") command.append("localhost:0") command.append("{0}".format(BUCKD_CLIENT_TIMEOUT_MILLIS)) ''' Change the process group of the child buckd process so that when this script is interrupted, it does not kill buckd. ''' def preexec_func(): os.setpgrp() process = subprocess.Popen( command, cwd=self._buck_project.root, preexec_fn=preexec_func) buckd_port = None for i in range(100): if buckd_port: break try: with open(ngserver_output_path) as f: for line in f: match = BUCKD_LOG_FILE_PATTERN.match(line) if match: buckd_port = match.group(1) break except IOError as e: pass finally: time.sleep(0.1) else: print( "nailgun server did not respond after 10s. Aborting buckd.", file=sys.stderr) return self._buck_project.save_buckd_port(buckd_port) self._buck_project.save_buckd_version(buck_version_uid) self._buck_project.update_buckd_run_count(0)