4

I am getting this error from the PyRFC library:

Traceback (most recent call last):
...
  File "/.../sap_connection.py", line 486, in get_connection
    return Connection(**get_connection_dict(contact_host))
  File "src/pyrfc/_pyrfc.pyx", line 182, in pyrfc._pyrfc.Connection.__init__
  File "src/pyrfc/_pyrfc.pyx", line 226, in pyrfc._pyrfc.Connection._open
  File "src/pyrfc/_pyrfc.pyx", line 256, in pyrfc._pyrfc.Connection._error
pyrfc._exception.CommunicationError: RFC_COMMUNICATION_FAILURE (rc=1): key=RFC_COMMUNICATION_FAILURE, message=
LOCATION    CPIC (TCP/IP) on local host with Unicode
ERROR       max no of 200 conversations exceeded
TIME        Wed Dec  4 13:53:22 2019
RELEASE     753
COMPONENT   CPIC (TCP/IP) with Unicode
VERSION     3
RC          466
MODULE      /bas/753_REL/src/krn/si/cpic/r3cpic.c
LINE        15830
COUNTER     201
 [MSG: class=, type=, number=, v1-4:=;;;]

Up to now I create a lot Connection instances and never explicitly close them.

If the Python process starts again (via linux cron job), then the RFC call works fine.

What should I do:

  • close the Connection explicitly?
  • reuse the Connection?
  • something else?

Related issue: https://github.com/SAP/PyRFC/issues/150

Suncatcher
  • 10,355
  • 10
  • 52
  • 90
guettli
  • 25,042
  • 81
  • 346
  • 663

3 Answers3

3

There are SAP notes exists about this error. It says there is limit on server side and you need to limit your client. Note 316877 included server side parameter for increasing size.
It make sense to close connection. Because RFC working on TCP/IP level, it hasn't got auto close routine after response look like rest/http.

mkysoft
  • 5,392
  • 1
  • 21
  • 30
  • 1
    Now I found the relevant docs: https://sap.github.io/PyRFC/pyrfc.html#pyrfc.Connection.close The client needs to close (or reuse) the connection. Creating new Connections for every call will sooner or later reach the limit. Thank you! – guettli Dec 05 '19 at 07:56
2

I use this StatelessConnection now:

from pyrfc import Connection
class StatelessConnection(Connection):
    def call(self, rfc_name, **kwargs):
        try:
            return super(StatelessConnection, self).call(rfc_name, **kwargs)
        finally:
            self.close()

The performance might be a bit lower, but it makes the overall handling a lot easier.

... I compared the performance. How much do you loose if you close the connection after every call?

for i in range(1000):
    #conn.close()
    print(i, conn.call('RFC_PING'))

The duration was equal on my system - with "close()" and without "close()": 28 seconds.

Maybe it would make sense to make StatelessConnection the default in PyRFC?

guettli
  • 25,042
  • 81
  • 346
  • 663
  • 2
    Why would you prefer that over reusing an already opened connection? – Jagger Dec 06 '19 at 07:16
  • @Jagger I love "stateless". Keeping an open connection is a state. It is easier to have not state. For me the question is: What benefits do I gain if I go the more complicated way. According to my small test, I gain nothing. Speed is the same. This might be different if establishing the connection is very slow, but this does not seem to be the case in my setup. About stateless: https://github.com/guettli/programming-guidelines/blob/master/README.md#stateless – guettli Dec 06 '19 at 09:15
  • 1
    PRO of stateless session: less issues with poorly written non re-entrant code. – phil soady Dec 15 '19 at 22:49
1

The previous answers are only "partially" correct, because we have to consider that the old SAP note 316877, which is mentioned here, is about SAP ITS, a component that used to run on the same host as the ABAP system. Therefore "client" and "server" are the same host in that case, which confuses matters...

The truth is: there is a limit on both sides, external RFC program as well as ABAP backend. You can see, which limit you are hitting, by checking the LOCATION field of the error message. In your case you are hitting the client-side limit:

LOCATION    CPIC (TCP/IP) on local host ... with Unicode
  • The CPIC library, which is linked into every external RFC program, has a default connection limit of 200. You can change this value by setting the following environment variable in the environment, where the external program is running:

    export CPIC_MAX_CONV=300

    In addition, most RFC SDKs export an API, which allows setting this value programmatically, e.g.

    • NW RFC Library: RfcSetMaximumCpicConversations(300, &errorInfo);
    • SAP JCo: JCo.setProperty("jco.cpic_maxconv", "300");
    • SAP NCo: GeneralConfiguration.CPICMaxConnections = 300; I don't know, whether PyRFC also exposes such an API.

    Finally, the limit can also be set via a configuration parameter:

    • NW RFC Library: in sapnwrfc.ini file set MAX_CPIC_CONVERSATIONS=300

      (As PyRFC is based on NW RFC Library, this should also work for PyRFC.)

    • SAP JCo: (doesn't have a central config file)

    • SAP NCo: in app.config file set

<SAP.Middleware.Connector>
  <GeneralSettings cpicMaxConnections=300 />
</SAP.Middleware.Connector>
  • The ABAP backend system has a default limit of 500. It can be changed by setting the following profile parameter: rdisp/max_comm_entries

On the question, whether connections should be closed and when, you not only need to consider the impact on your client program, but also the impact on the ABAP backend system! Every open RFC connection allocates one user session in the backend system, and this consumes quite a significant amount of resources, which are no longer available to other users that want to log on and use the system (either via RFC or via SAPGui).

And also, you need to consider that when leaving a connection open that is no longer used, you are not only consuming a seat in your own program, you are also consuming one of the 500 seats in the backend system. This means, if there are three "misbehaving" programs with such a connection leak, the 500 conversations in the backend are quickly blocked, and then the backend cannot accept further connections from other programs or SAP systems.

So the first point to note is, that you should close a connection as soon as you no longer need it, in order to reduce the strain on the backend.

Next you need to consider that opening a connection, results in the backend kernel performing the "login procedure", which is quite time consuming. I don't believe the above test with 1000 calls in a loop. Something must be wrong here. The performance will definitely be slower, if you open and close a new connection for every single call. This is true especially when using SNC instead of user/password logon, because the SNC handshake (with exchanging and validating certificates on both sides) is very expensive.

So the best way definitely is:

  1. Open a connection
  2. Do all RFC calls you currently need to do via this connection
  3. Afterwards close the connection
Lanzelot
  • 15,976
  • 4
  • 18
  • 14