Как в Oracle отменить разорванное соединение?

Этот код написан на питоне, но в основном он использует OCI, поэтому его можно воспроизвести на любом другом языке:

import cx_Oracle as db
dsn = '(DESCRIPTION =(CONNECT_TIMEOUT=3)(RETRY_COUNT=1)(TRANSPORT_CONNECT_TIMEOUT=3)(ADDRESS_LIST =(ADDRESS = (PROTOCOL = TCP)(HOST = SOME_HOST)(PORT = 1531)))(CONNECT_DATA =(SERVICE_NAME = SOME_NAME)))'
connect_string = "LOGIN/PASSWORD@%s" % dsn
conn = db.connect(connect_string)
conn.ping() # WILL HANG FOREVER!!!

Если SOME_HOST не работает, это зависнет навсегда!

И это не связано с OCIPing - если я заменю:

ping()

с:

cursor = conn.cursor()
cursor.execute('SELECT 1 FROM DUAL') # HANG FOREVER AS WELL

Это тоже будет висеть.

Я использую SQL*Plus: выпуск 11.2.0.3.0 Production, среда, 6 ноября, 12:17:09 2013 г..

Я пытался обернуть этот код в поток и ждать того же времени, что и убить поток, но это не работает. Этот код создает сам поток, и его невозможно убить из python. Есть ли у вас идеи, как восстановиться?


person mnowotka    schedule 06.11.2013    source источник


Ответы (3)


Короткий ответ заключается в использовании блоков try/except/finally, но если часть вашего кода действительно ожидает условия, которое никогда не будет выполнено, вам нужно реализовать внутренний тайм-аут. Есть множество способов сделать это. Вы можете адаптировать решение этой проблемы к своим потребностям.

Надеюсь это поможет.

person Spade    schedule 21.01.2014
comment
Если подумать, то окажется, что можно реализовать внутренний тайм-аут, который достаточно хорош для этой ситуации. - person mnowotka; 21.01.2014
comment
Вы одобряете ответ, просите о дополнительной помощи или отвергаете ответ? - person Spade; 22.01.2014

У меня были те же проблемы с прерыванием conn.ping().
Теперь я использую следующую конструкцию:

from threading import Timer

pingTimeout = 10 # sec

# ...

def breakConnection():
    conn.cancel()
    connection = False

try:
    t = Timer(pingTimeout, breakConnection)
    cursor = conn.cursor()
    cursor.execute('SELECT 1 FROM DUAL')
    t.close()
    cursor.close()
except Exception:
    connection = False

if not connection:
    print 'Trying to reconnect...'
    # ...

Это грязный способ, но он работает.

И реальный способ проверить, можно ли использовать соединение, - это выполнить оператор приложения, который вы хотите запустить (я не имею в виду SELECT 1 FROM DUAL). Затем попробуйте повторить попытку, если поймаете исключение.

person Pavlo Bashynskyi    schedule 17.08.2018

если вы хотите близкое соединение, попробуйте

conn.close()
person Артем Романюк    schedule 19.12.2015
comment
Да, но как это будет выполняться, если оно зависает? - person Nathan Tuggy; 20.12.2015