| 143 | |
| 144 | |
| 145 | def _serving(sock, addr, opts, load_library): |
| 146 | logger.info(f"connected from {addr}") |
| 147 | work_path = utils.tempdir() |
| 148 | old_cwd = os.getcwd() |
| 149 | os.chdir(work_path.path) # Avoiding file name conflict between sessions. |
| 150 | logger.info(f"start serving at {work_path.path}") |
| 151 | |
| 152 | server_proc = multiprocessing.Process(target=_serve_loop, args=(sock, load_library, work_path)) |
| 153 | server_proc.start() |
| 154 | server_proc.join(opts.get("timeout", None)) # Wait until finish or timeout. |
| 155 | |
| 156 | if server_proc.is_alive(): |
| 157 | logger.info("timeout in RPC session, kill..") |
| 158 | _ffi_api.ReturnException( |
| 159 | sock.fileno(), |
| 160 | f"RPCSessionTimeoutError: Your {opts['timeout']}s session has expired, " |
| 161 | f'try to increase the "session_timeout" value.', |
| 162 | ) |
| 163 | |
| 164 | try: |
| 165 | import psutil # pylint: disable=import-outside-toplevel |
| 166 | |
| 167 | # Terminate worker children firstly. |
| 168 | for child in psutil.Process(server_proc.pid).children(recursive=True): |
| 169 | child.terminate() |
| 170 | except ImportError: |
| 171 | # Don't dependent `psutil` hardly, because it isn't a pure Python |
| 172 | # package and maybe hard to be installed on some platforms. |
| 173 | pass |
| 174 | server_proc.terminate() |
| 175 | elif server_proc.exitcode != 0: |
| 176 | raise RuntimeError( |
| 177 | f"Child process {server_proc.pid} exited unsuccessfully " |
| 178 | f"with error code {server_proc.exitcode}" |
| 179 | ) |
| 180 | |
| 181 | logger.info(f"finish serving {addr}") |
| 182 | os.chdir(old_cwd) |
| 183 | work_path.remove() |
| 184 | sock.close() |
| 185 | |
| 186 | |
| 187 | def _listen_loop(sock, port, rpc_key, tracker_addr, load_library, custom_addr): |