Hacktoberfest 2026: những issue maintainer đã đánh dấu cho tháng Mười, đang mở và phù hợp người mới. Xem issue Hacktoberfest

Async Thin: call_timeout returns DPY-4024 before RESET completes

Đang mở
#624 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.

Đánh giá

Độ khó
4/5
Thời gian dự kiến
1-2 ngày
Mức phù hợp với người mới
45/100
Loại issue
Lỗi
Độ rõ ràng
Đặc tả rõ ràng
Mức độ hoạt động
Sôi nổi
Công nghệ
python

Hướng nghiên cứu

Start by reading BaseAsyncProtocol._process_timeout_helper() and trace how _break_external() and _receive_packet(message) handle DATA and RESET marker packets. Compare that flow with the packet sequence described in the issue and inspect related async protocol tests for timeout recovery. Done means a timed out call completes BREAK/RESET recovery before raising DPY-4024, and a subsequent statement does not fail with DPY-4011.

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

Mô tả

bug
  1. What versions are you using?
  • Oracle Database Free 23.5.0.24.7 (local testing); Observed in production against Oracle Database 19c.
  • python-oracledb 4.0.2 and 26.0.1, Thin mode. The same timeout-helper code is present on main (c92c8420).
  • Python 3.13, asyncio, on macOS arm64 and Linux arm64.
  • Production also uses uvloop and SQLAlchemy 2.0 (oracle+oracledb_async), but the reproduction below uses native python-oracledb only.
  • Oracle Client: not applicable (Thin mode).
  1. Is it an error or a hang or a crash?

An error after a timeout, followed by a delayed failure when reusing a connection that still reports healthy.

  1. What error(s) or behavior you are seeing?

With call_timeout = 500, a statement that completes between approximately 500 and 1000 ms can raise DPY-4024 while connection.is_healthy() returns True. The next statement on that connection waits approximately 1 second and fails with:

DPY-4011: the database or network closed the connection
socket timed out while recovering from previous socket timeout

Representative output from the original reproduction on 26.0.1, Linux arm64:

  sleep=0.6: call 1 DPY-4024, is_healthy=True
    call 2 DPY-4011 after 1.01s
  sleep=0.7: call 1 DPY-4024, is_healthy=True
    call 2 DPY-4011 after 1.01s
  sleep=0.8: call 1 DPY-4024, is_healthy=True
    call 2 DPY-4011 after 1.00s

This is timing-dependent: some runs recover successfully or return ORA-01013 on the next call. The same behavior was reproduced on 4.0.2.

Source inspection and packet traces point to incomplete BREAK/RESET recovery in BaseAsyncProtocol._process_timeout_helper():

self._break_external()
await self._receive_packet(message)
self._break_in_progress = False
errors._raise_err(errors.ERR_CALL_TIMEOUT_EXCEEDED, timeout=timeout)

If the first packet received is the completed statement's DATA response rather than a MARKER, the helper raises DPY-4024 without completing RESET. The trace shows the server's RESET marker arriving without a client RESET response. The next call clears buffered packets and sends a request while the server is still waiting for RESET.

  1. Does your application call init_oracle_client()?

No. Thin mode.

  1. Include a runnable Python script that shows the problem.
import asyncio
import os
import platform
import sys
import time

import oracledb

PARAMS = dict(
    user=os.environ["ORACLE_USER"],
    password=os.environ["ORACLE_PASSWORD"],
    dsn=os.environ["ORACLE_DSN"],
)

async def main():
   
    for sleep_s in (0.55, 0.6, 0.7, 0.8, 0.9):
        async with oracledb.connect_async(**PARAMS) as conn:
            print("connection.version:", conn.version)
            conn.call_timeout = 500
            with conn.cursor() as cur:
                try:
                    await cur.execute(
                        "begin dbms_session.sleep(:s); end;", [sleep_s]
                    )
                except oracledb.DatabaseError as exc:
                    print(
                        f"  sleep={sleep_s}: call 1 {exc.args[0].full_code}, "
                        f"is_healthy={conn.is_healthy()}"
                    )

                start = time.monotonic()
                try:
                    await cur.execute("select 1 from dual")
                    print("    call 2 ok")
                except oracledb.DatabaseError as exc:
                    print(
                        f"    call 2 {exc.args[0].full_code} "
                        f"after {time.monotonic() - start:.2f}s"
                    )


asyncio.run(main())
Ngôn ngữ chính
Python
Star
455
Fork
119
Chỉ số merge pull request
Không có pull request nào được merge trong 30 ngày

Chuẩn bị môi trường

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.

Issue khác của oracle/python-oracledb

Tất cả issue của oracle/python-oracledb

Issue tương tự

Thêm issue về Python

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.