Calling Function Modules in Parallel Universes
When you call a function module in a remote destination, a new internal mode and within it, an internal session is created in the remote system. So much is obvious.
But few people know how powerful (but also how dangerous) it can be to call an RFC-enabled function module of the local system with CALL FUNCTION … DESTINATION. (Either you can look up the destinatination of the local system via the logical system ID stored in table T000 or you spare yourself the trouble and just use destination ‘NONE’).
When using destination ‘NONE’, the function module will be executed in a new internal session under the same user id, which means:
- The new internal session will contain new instances of every main program that is called inside it.
- The state of the global memory of any function group, static attributes of global classes, and memories of main programs accessed through external performs are initialized “in a parallel universe” with respect to the caller’s internal mode.
- This concerns for example the memory of the Business Application Log (BAL) and the memories of function groups that bundle data for updates IN UPDATE TASK and make them transparently available to callers according to the BAPI programming paradigm.
- Locks are not inherited. Requests for a lock for a key that is already locked by the calling internal session will fail.
- Commits and Rollbacks (both at database and LUW level) from the called function module’s internal mode have no effect on the caller’s internal mode and vice versa (except of course through the contents of the database).
The last effect is actually quite useful if you know exactly what you’re doing. It allows you to open an independent transaction or Logical Unit of Work that is isolated from the rest of your system state. I.e. it can be quite beneficial to call destination ‘NONE’ and create a new “parallel universe” where the static attributes of every global class are initial, and that won’t be affected by your COMMIT WORKs or affect you with its own COMMIT WORKs (or ROLLBACK WORKs, respectively).
- You want to create a log entry in update task for a ROLLBACK WORK (or using OpenSQL for a database rollback) and you want to protect this from the effect of the very rollback it is documenting.
- You want to start an error workflow IN UPDATE TASK and a ROLLBACK WORK in your internal mode should not roll back the function module registration.
- You want to call a function module that you know or suspect causes commits or rollbacks which would mess up your own transaction handling (say, because you are working with OO transactions of the ABAP Object Services).
- You want to create a sub-transaction like behaviour – say you want to call a BAPI that creates a business partner and you want to be able to roll it back later, but you don’t want the rollback to affect your main process or, and this is really fun, another business partner you’re also creating.
I like to think of the pseudo-remote internal session as a new bubble which is perfectly isolated from the bubble of the calling process.
Here are a few useful facts for working with bubbles:
- The second bubble lives as long as the first one does.
- You can call the second bubble repeatedly from within the first bubble.
- Subsequent calls to the same destination but different function modules will be executed in the same bubble.
- If you change the state of the global memory of a function group through CALL FUNCTION … DESTINATION … it will still be this way when you call this or a different function module in the same destination later. Try it out with a pair of RFC-enabled function modules Z_RFC_SET and Z_RFC_GET that operate on the same variable declared in the TOP-Include of the function group.
- It is even possible to call back from the second bubble to the first bubble (also repeatedly) using CALL FUNCTION … DESTINATION ‘BACK’.
- Other means of creating new bubbles include SUBMIT … AND RETURN and CALL TRANSACTION, but it’s more difficult to communicate with these bubbles and they burst as soon as the called programs have finished execution.
- You can control the LUWs in the other bubble by calling BAPI_TRANSACTION_COMMIT and BAPI_TRANSACTION_ROLLBACK in destination ‘NONE’ or ‘BACK’.
- You can write RFC-enabled function modules that wrap function modules DB_COMMIT and DB_ROLLBACK to control the database transactions in the other bubble.
- Creating a new bubble is expensive in terms of system resources, and switching between bubbles is less expensive, but costs more than a local function call. The contents of the first internal session are moved out of the work process’ roll area, and the contents of the second internal session are loaded into it. When you return, the reverse happens.
If you don’t understand some of the above points, by all means forget this blog, or you might mess up your system and create errors that will be very hard to debug.
If you understand these things exactly, you can do some magic with them. RFCs offer so much fun – have you studied the asynchronous RFC for parallel processing? Anyway, enjoy.
- Horst Keller, also known as the ABAP Geek, wrote an excellent series of weblogs that have been bundled into this article: ABAP Geek Webog Series
- SAP Documentation on “Calling Remote Functions Locally”