# Buggy code
def _worker_process_main(
    self,
    judge_process_conn: "multiprocessing.connection.Connection",
    worker_process_conn: "multiprocessing.connection.Connection",
) -> None:
    """
    Main body of judge worker process, which handles grading and sends grading results to the judge controller via
    IPC.
    """
    worker_process_conn.close()
    setproctitle(multiprocessing.current_process().name)

    def _ipc_recv_thread_main() -> None:
        """
        Worker thread that listens for incoming IPC messages from the judge controller.
        """
        while True:
            try:
                ipc_type, data = judge_process_conn.recv()
            except:  # noqa: E722, whatever happened, we have to abort now.
                logger.exception("Judge unexpectedly hung up!")
                self._do_abort()
                return

            if ipc_type == IPC.BYE:
                return
            elif ipc_type == IPC.REQUEST_ABORT:
                self._do_abort()
            else:
                raise RuntimeError(
                    "worker got unexpected IPC message from judge: %s"
                    % ((ipc_type, data),)
                )

    ipc_recv_thread = None
    try:
        judge_process_conn.send((IPC.HELLO, ()))

        ipc_recv_thread = threading.Thread(target=_ipc_recv_thread_main, daemon=True)
        ipc_recv_thread.start()

        for ipc_msg in self._grade_cases():
            judge_process_conn.send(ipc_msg)

        judge_process_conn.send((IPC.BYE, ()))
    except BrokenPipeError:
        # There's nothing we can do about this... the general except branch would just fail again. Just re-raise and
        # hope for the best.
        raise
    except:  # noqa: E722, we explicitly want to notify the parent of everything
        # We can't pickle the whole traceback object, so just send the formatted exception.
        message = "".join(traceback.format_exception(*sys.exc_info()))
        judge_process_conn.send((IPC.UNHANDLED_EXCEPTION, (message,)))
        judge_process_conn.send((IPC.BYE, ()))
    finally:
        if ipc_recv_thread is not None:
            # We may have failed before sending the IPC.BYE down the connection, in which case the judge will never
            # close its side of the connection -- so `ipc_recv_thread` will never exit. But we can't wait forever in
            # this case, since we're blocking the main judge from proceeding.
            ipc_recv_thread.join(timeout=IPC_TEARDOWN_TIMEOUT)
            if ipc_recv_thread.is_alive():
                logger.error(
                    "Judge IPC recv thread is still alive after timeout, shutting worker down anyway!"
                )

        # FIXME(tbrindus): we need to do this because cleaning up temporary directories happens on __del__, which
        # won't get called if we exit the process right now (so we'd leak all files created by the grader). This
        # should be refactored to have an explicit `cleanup()` or similar, rather than relying on refcounting
        # working out.
        self.grader = None


# Traceback (BrokenPipeError)
ERROR 2020-07-14 02:50:42,786 12712 judge Judge IPC recv thread is still alive after timeout, shutting worker down anyway!
Process DMOJ Judge Handler for boi2019p1/2202447:
Traceback (most recent call last):
File "/usr/lib/python3.8/multiprocessing/process.py", line 315, in _bootstrap
self.run()
File "/usr/lib/python3.8/multiprocessing/process.py", line 108, in run
self._target(*self._args, **self._kwargs)
File "/judge/dmoj/judge.py", line 381, in _worker_process_main
for ipc_msg in self._grade_cases():
File "/judge/dmoj/judge.py", line 453, in _grade_cases
result = self.grader.grade(case)
File "/judge/dmoj/graders/standard.py", line 22, in grade
error = self._interact_with_process(case, result, input)
File "/problems/boi/boi2019/boi2019p1/flash.py", line 28, in _interact_with_process
interactors[i].writeln(int(i >= 2))
File "/judge/dmoj/graders/interactive.py", line 87, in writeln
self.process.stdin.flush()
BrokenPipeError: [Errno 32] Broken pipe
ERROR 2020-07-14 02:50:42,792 56 judge Failed to read IPC message from worker!
ERROR 2020-07-14 02:50:42,793 56 judge Traceback (most recent call last):
File "/judge/dmoj/judge.py", line 152, in _grading_thread_main
for ipc_type, data in self.current_judge_worker.communicate():
File "/judge/dmoj/judge.py", line 306, in communicate
ipc_type, data = self.worker_process_conn.recv()
File "/usr/lib/python3.8/multiprocessing/connection.py", line 250, in recv
buf = self._recv_bytes()
File "/usr/lib/python3.8/multiprocessing/connection.py", line 414, in _recv_bytes
buf = self._recv(4)
File "/usr/lib/python3.8/multiprocessing/connection.py", line 383, in _recv
raise EOFError
EOFError

# Fixed code
def _worker_process_main(
    self,
    judge_process_conn: "multiprocessing.connection.Connection",
    worker_process_conn: "multiprocessing.connection.Connection",
) -> None:
    """
    Main body of judge worker process, which handles grading and sends grading results to the judge controller via
    IPC.
    """
    worker_process_conn.close()
    setproctitle(multiprocessing.current_process().name)

    def _ipc_recv_thread_main() -> None:
        """
        Worker thread that listens for incoming IPC messages from the judge controller.
        """
        while True:
            try:
                ipc_type, data = judge_process_conn.recv()
            except:  # noqa: E722, whatever happened, we have to abort now.
                logger.exception("Judge unexpectedly hung up!")
                self._do_abort()
                return

            if ipc_type == IPC.BYE:
                return
            elif ipc_type == IPC.REQUEST_ABORT:
                self._do_abort()
            else:
                raise RuntimeError(
                    "worker got unexpected IPC message from judge: %s"
                    % ((ipc_type, data),)
                )

    ipc_recv_thread = None
    try:
        judge_process_conn.send((IPC.HELLO, ()))

        ipc_recv_thread = threading.Thread(target=_ipc_recv_thread_main, daemon=True)
        ipc_recv_thread.start()

        case_gen = self._grade_cases()
        while True:
            try:
                ipc_msg = next(case_gen)
            except StopIteration:
                break
            except Exception as exc:
                # We need to wrap all exceptions raised by a grader, since a grader can raise a `BrokenPipeError`
                # that's indistinguishable from one caused by `judge_process_conn.send`, but should be handled
                # differently (i.e. not quit the judge).
                raise InternalError("grader raised exception while grading") from exc

            judge_process_conn.send(ipc_msg)

        judge_process_conn.send((IPC.BYE, ()))
    except BrokenPipeError:
        # There's nothing we can do about this... the general except branch would just fail again. Just re-raise and
        # hope for the best.
        raise
    except:  # noqa: E722, we explicitly want to notify the parent of everything
        # We can't pickle the whole traceback object, so just send the formatted exception.
        message = "".join(traceback.format_exception(*sys.exc_info()))
        judge_process_conn.send((IPC.UNHANDLED_EXCEPTION, (message,)))
        judge_process_conn.send((IPC.BYE, ()))
    finally:
        if ipc_recv_thread is not None:
            # We may have failed before sending the IPC.BYE down the connection, in which case the judge will never
            # close its side of the connection -- so `ipc_recv_thread` will never exit. But we can't wait forever in
            # this case, since we're blocking the main judge from proceeding.
            ipc_recv_thread.join(timeout=IPC_TEARDOWN_TIMEOUT)
            if ipc_recv_thread.is_alive():
                logger.error(
                    "Judge IPC recv thread is still alive after timeout, shutting worker down anyway!"
                )

        # FIXME(tbrindus): we need to do this because cleaning up temporary directories happens on __del__, which
        # won't get called if we exit the process right now (so we'd leak all files created by the grader). This
        # should be refactored to have an explicit `cleanup()` or similar, rather than relying on refcounting
        # working out.
        self.grader = None