PyRFC Call - Explanation of options parameter in call() method #310
-
Hi PyRFC community, I'm using PyRFC as a client to call an RFC in S/4HANA. Most of the times the call works fine but sometimes I get an error like this: Using call options -> {'timeout': 300} ...
Connection Parameters -> {'user': '...', 'passwd': '...', 'client': '100', 'trace': '3', 'lang': 'EN', 'ashost': '...', 'sysnr': '00', 'sysid': 'TM6'}
Failed to call RFC -> ZFM_GECKO_RFC_CR_UPD_ALL_WKSP; error -> RFC_COMMUNICATION_FAILURE (rc=1): key=RFC_COMMUNICATION_FAILURE, message=
LOCATION CPIC (TCP/IP) on local host with Unicode
ERROR connection to partner '...:3300' broken
TIME Sat Apr 8 01:18:27 2023
RELEASE 753
COMPONENT NI (network interface)
VERSION 40
RC -6
MODULE /bas/753_REL/src/base/ni/nixxi.cpp
LINE 5434
DETAIL NiIRead: P=52.16.217.14:3300; L=10.24.22.102:59516
SYSTEM CALL recv
ERRNO 104
ERRNO TEXT Connection reset by peer
COUNTER 18
[MSG: class=, type=, number=, v1-4:=;;;] While this problem may well be on the SAP side I'm wondering how to debug this in a good way with PyRFC. I tried to understand what "call options" are available and tried to pass a { timeout : 300} . But it seems this is not really becoming effective (the call hung 35mins before bailing out and not returning with an error after 5mins (300 secs)). https://github.com/SAP/PyRFC/blob/main/doc/client.rst list "dtime", "rstrip", "return_import_params" https://sap.github.io/PyRFC/pyrfc.html gives just one example of an option: "skip" Is there a better documentation for the different values the "options" dict can have in call() method? In particular, how can I submit a timeout parameter that really works? |
Beta Was this translation helpful? Give feedback.
Replies: 4 comments 3 replies
-
Hello @Diefenbruch and welcome to Community! Thank you for catching this documentation gap. The documentation of client RFC connection and RFC call options will be improved in next PyRFC version, coming soon. There is no Feedback welcome if these options would be really helpful or pattern below is enough? Cancel using import sys
from threading import Timer
from pyrfc import Connection, RFCError
c = Connection(dest=sys.argv[1])
# cancel client connection after 5 seconds
Timer(5, c.cancel).start()
try:
# 10 seconds long RFC call
r = c.call("RFC_PING_AND_WAIT", SECONDS=10)
except RFCError as ex:
print(ex) Cancel using import sys
from threading import Timer
from pyrfc import Connection, RFCError, cancel_connection
c = Connection(dest=sys.argv[1])
# cancel client connection after 5 seconds
Timer(5, cancel_connection, args=(c,)).start()
try:
# 10 seconds long RFC call
r = c.call("RFC_PING_AND_WAIT", SECONDS=10)
except RFCError as ex:
print(ex) |
Beta Was this translation helpful? Give feedback.
-
@bsrdjan I don't think I understand this feature. Well, I understand that a threaded timer termininates and re-opend the connection if the call takes longer than X seconds. But I don't understand how the connection will stay open if the call succeeds within the timeout limit. Won't the threaded timer cancel the connection anyway, even if the call did not run ino a timeout? Maybe the connection is already processing the second / third / fourth call within the timeout limit. I see you added test cases for the timeout scenario and assert that the handle changes. I would be more confident in this feature if there was also a test that asserts that the handle stays the same if we do not run into a timeout. e.g. old_handle = client.handle
for _ in range(5)
# Cancel next RFC call after 5 seconds
Timer(5, client.cancel).start()
# RFC call taking 3 seconds, should not be cancelled
r = client.call("RFC_PING_AND_WAIT", SECONDS=3)
# ensure connection was not cancelled
assert client.alive is True
assert client.handle == old_handle If this is already the case then I'm sorry, I just don't get what is preventing the connection from being cancelled in this scenario. |
Beta Was this translation helpful? Give feedback.
-
good point and here the re-factored approach. The timeout can be set at connection level, as connection option, and be valid for all RFC calls over that connection. It can be set also as RFC call option ( The usage pattern: from pyrfc import Connection, RFCError
c = Connection(dest="TEST", config={"timeout": 20})
try:
# 10 seconds long RFC call, cancelled after 5 seconds,
# despite 15 seconds timeout at connection level
r = c.call("RFC_PING_AND_WAIT", options={"timeout": 5}, SECONDS=10)
except RFCError as ex:
print(ex.code, ex.key, ex.message)
# 7 RFC_CANCELED Connection was canceled: 5059097088. New handle: 4798322688 or from pyrfc import Connection, RFCError
c = Connection(dest=sys.argv[1], config={"timeout": 5})
try:
# 10 seconds long RFC call cancelled after 5 seconds
# because of timeout set at connection level, for all RFC calls
r = c.call("RFC_PING_AND_WAIT", SECONDS=10)
except RFCError as ex:
print(ex.code, ex.key, ex.message)
# 7 RFC_CANCELED Connection was canceled: 5067486720. New handle: 4806705664 |
Beta Was this translation helpful? Give feedback.
-
Timeout is implemented and documented in 2.8.0 release: Examples: SAP/PyRFC/examples/timeout |
Beta Was this translation helpful? Give feedback.
Timeout is implemented and documented in 2.8.0 release:
Examples: SAP/PyRFC/examples/timeout