As I wrote last week, we had some problems with data not being released when making a call from R/3 to APO via RFC. I expected the data – the sumulation sessions of APO liveCache – to be cleaned up as soon as the RFC call is getting back into R/3, but they remained in memory as long as our dialog transaction on R/3 side was kept open. This was a kind of concern for our team as a problem potentially affecting liveCache performance, though in liveCache monitoring (LC10), the memory consumed by those simsessions looked quite innocent in comparison with others.
So, what was that? Whenever we want to read some liveCache data, we need to open a “session” first, for it is a required parameter to most of APO functions reading data from or writing to liveCache. Exceptions are of course BAPIs, that are dedicated to be called easily from outside. And if you are in some user exit of BADi, you don’t need the session because normally you are given one as a parameter.
So, before we start, we usually create a new session with the function /SAPAPO/RRP_SIMSESSION_CREATE. If it’s being done in a “short-living” fashion, like a report that is run and then exited, one’s sessions are gone very soon. But ours was kept open by some users, sometimes for hours. LiveCache deletes the sessions that it finds to be too old (as defined in customizing), but we wanted them to go away faster. In the same function group as CREATE function, there is the function /SAPAPO/RRP_SIMSESSION_LEAVE, but I found it to be slightly suspicious, for it is used by SAP itself only at couple of places. In addition, the code I had to fix could be calling CREATE function several times. Do I have to call LEAVE every time right after? Or are there any other ways?
I decided to search on OSS. There are many notes dealing with sessions that remain open, and I looked at how SAP solved the problem. They did it better than just calling LEAVE. Instead, before calling CREATE, they try to find any existing session created earlier in the program by calling /SAPAPO/RRP_SIMSESSION_GET. If it fails, they create a new one and set a flag (a global variable) indicating that they have to release the created session. I decided to use the same logic, so the whole sequence looked like:
* Try to get an existing session first call function '/SAPAPO/RRP_SIMSESSION_GET' importing ev_simsession = lv_simsession. if lv_simsession is initial. * Create a new simsession call function '/SAPAPO/RRP_SIMSESSION_CREATE' exporting iv_simid = ls_params-simversion iv_change_mode = gc_false importing ev_simsession = lv_simsession. gf_sims_created = gc_true. endif. * ..... now depending on program conditions, * follow more GET/CREATE blocks, with GET * most likely returning the session created earlier * And now, cleanup: * Did we create any sessions? if gf_sims_created = gc_true. * Check if there are any sessions still open * (who knows - maybe they are deleted already) call function '/SAPAPO/RRP_SIMSESSION_GET' importing ev_simsession = lf_simsession. if not lf_simsession is initial. call function '/SAPAPO/TSIM_SIMULATION_CANCEL' exceptions others = 0. gf_sims_created = gc_false. endif. endif.
Update: as our practice has shown, this way of releasing APO SIM sessions is good only if your program does exactly one RFC call to APO. If you do two, the second one will fail because APO will try to reuse the old session which is already destroyed – the result of APO keeping the data and program state from the first call and therefore some global variable not being initialized. So, in this case the right way is calling the /SAPAPO/RRP_SIMSESSION_LEAVE.