python / python/cpython

Race condition in test_traceback_when_child_process_terminates_abruptly

Đang mở
#143,620 0 bình luận 0 reaction 0 người được giao Xem trên GitHub

Chưa có ai nhận issue này.

tests type-bug
Ngôn ngữ chính
Python
Star
77.2k
Fork
35.9k
Chỉ số merge pull request
Chỉ số pull request đang chờ

Mô tả

Bug report

Bug description:

I have been observing that on my local build of main branch when I run the test suite, I occasionally am getting a failed test. Failure here:

0:01:56 load avg: 2.52 [ 39/498] test.test_concurrent_futures.test_interpreter_pool passed

0:01:56 load avg: 2.52 [ 40/498] test.test_concurrent_futures.test_process_pool

test test.test_concurrent_futures.test_process_pool failed -- Traceback (most recent call last):

  File "/Users/a12k/opt/cpython/Lib/test/test_concurrent_futures/test_process_pool.py", line 119, in test_traceback_when_child_process_terminates_abruptly

    self.assertIsInstance(cause, futures.process._RemoteTraceback)

    ~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

AssertionError: None is not an instance of <class 'concurrent.futures.process._RemoteTraceback'>

0:02:08 load avg: 2.97 [ 40/498/1] test.test_concurrent_futures.test_process_pool failed (1 failure)
0:02:08 load avg: 2.97 [ 41/498/1] test.test_concurrent_futures.test_shutdown

I tried a few different ways of repro-ing this deterministically, mostly letting it and the few tests that preceded it run for an hour (./python.exe -m test -v -F test.test_concurrent_futures.test_process_pool, or ./python -m test -v -F test_concurrent_futures.test_deadlock test_concurrent_futures.test_interpreter_pool test_concurrent_futures.test_process_pool) until it failed.

I ended up forcing the fail in Lib/concurrent/futures/process.py which is as follows (insert at line 486 right after errors = [] all the way until # Mark pending tasks as failed.):

            if any(fn == os._exit for fn in [w.fn for w in self.pending_work_items.values()]):
                print("~~~ ARTIFICAL DELAY ~~~")
                for p in list(self.processes.values()):
                    # set exit code to None to simulate it not ready yet
                    object.__setattr__(p, "_exitcode", None)

            for p in self.processes.values():
                if p.exitcode is not None and p.exitcode != 0:
                    errors.append(f"Process {p.pid} terminated abruptly "
                                  f"with exit code {p.exitcode}")
            if errors:
                cause_str = "\n".join(errors)

        if cause_str and any(fn == os._exit for fn in [w.fn for w in self.pending_work_items.values()]):
            print("~~~ ARTIFICAL DELAY ~~~ Waiting to set __cause__ for 3 seconds")
            def delayed_set_cause():
                import time
                time.sleep(3)
                print("~~~ ARTIFICAL DELAY COMPLETE ~~~ setting __cause__")
                nonlocal bpe
                bpe.__cause__ = _RemoteTraceback(f"\n'''\n{cause_str}'''")

            # Set cause after delay
            threading.Thread(target=delayed_set_cause, daemon=True).start()
        elif cause_str:
            bpe.__cause__ = _RemoteTraceback(f"\n'''\n{cause_str}'''")

Basically forcing the race condition, setting the cause to None and delaying it. Not sure if this was all necessary, but that's how I was able to deterministically get it to continually fail.

I updated the test to account for this race condition by waiting for __cause__ to be populated and now the test passes. PR incoming for review.

CPython versions tested on:

CPython main branch

Operating systems tested on:

macOS

Linked PRs
  • gh-143621

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Hướng nghiên cứu

Bắt đầu với Lib/test/test_concurrent_futures/test_process_pool.py tại test_traceback_when_child_process_terminates_abruptly và kiểm tra cách xử lý liên quan trong Lib/concurrent/futures/process.py. Chạy lặp lại bài kiểm thử process-pool được chỉ định để tái hiện lỗi không liên tục. Hoàn tất khi bài kiểm thử luôn quan sát được _RemoteTraceback ожида ожида ожида dự kiến mà không có độ trễ nhân tạo.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Đánh giá

Công nghệ
python
Lĩnh vực
testing-qa
Loại issue
Lỗi
Độ khó
4/5
Thời gian dự kiến
3-5 ngày
Mức độ hoạt động
Đình trệ
Độ rõ ràng
Đặc tả rõ ràng
Mức phù hợp với người mới
15/100

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.