通过 RFC 多次调用函数
ME_INFORECORD_MAINTAIN_MULTI
失败,并显示短转储“达到 GUI 会话的最大数量”,但以相同方式调用时其他函数似乎不受会话限制。
我可以并行调用此函数的数量取决于我当前打开的 GUI 会话(SAP GUI 窗口)的数量。
例如,以下代码在 5 次调用后失败(我在发生转储的行的开头添加了
>>>
):
FORM CALL_BAPI_INFORECORD.
lv_taskname = |PIR-{ lv_sentjobs WIDTH = 3 ALIGN = RIGHT PAD = '0' }|.
DATA: lv_retry TYPE ABAP_BOOL.
lv_retry = ABAP_TRUE.
WHILE lv_retry = ABAP_TRUE.
lv_retry = ABAP_FALSE.
CALL FUNCTION 'ME_INFORECORD_MAINTAIN_MULTI'
STARTING NEW TASK lv_taskname
DESTINATION IN GROUP DEFAULT
PERFORMING RETURN_BAPI_INFORECORD ON END OF TASK
[...]
EXCEPTIONS
system_failure = 1 MESSAGE lv_exceptionmsg
communication_failure = 2 MESSAGE lv_exceptionmsg
resource_failure = 3
CASE sy-subrc.
WHEN 0.
lv_sentjobs = lv_sentjobs + 1.
WHEN 1 OR 2.
MESSAGE lv_exceptionmsg TYPE 'I'.
WRITE: / lv_taskname, ':', lv_exceptionmsg.
WHEN 3.
WAIT FOR ASYNCHRONOUS TASKS UNTIL lv_recvjobs = lv_sentjobs UP TO 300 SECONDS.
lv_retry = ABAP_TRUE.
WHEN OTHERS.
MESSAGE 'Unkown error.' TYPE 'I'.
ENDCASE.
ENDWHILE.
ENDFORM.
FORM RETURN_BAPI_INFORECORD USING TASKNAME.
DATA INFO LIKE RFCSI.
>>> RECEIVE RESULTS FROM FUNCTION 'ME_INFORECORD_MAINTAIN_MULTI'
IMPORTING
RFCSI_EXPORT = INFO
RETURN = GT_ME_INFORECORD_RETURN.
ENDFORM.
...但是以下代码在 10 个并行调用下运行良好:
FORM CALL_BAPI_MATERIAL.
lv_taskname = |MAT-{ lv_sentjobs WIDTH = 3 ALIGN = RIGHT PAD = '0' }|.
DATA: lv_retry TYPE ABAP_BOOL.
lv_retry = ABAP_TRUE.
WHILE lv_retry = ABAP_TRUE.
lv_retry = ABAP_FALSE.
CALL FUNCTION 'BAPI_MATERIAL_SAVEREPLICA'
STARTING NEW TASK lv_taskname
DESTINATION IN GROUP DEFAULT
PERFORMING RETURN_BAPI_MATERIAL ON END OF TASK
[...]
EXCEPTIONS
system_failure = 1 MESSAGE lv_exceptionmsg
communication_failure = 2 MESSAGE lv_exceptionmsg
resource_failure = 3.
CASE sy-subrc.
WHEN 0.
lv_sentjobs = lv_sentjobs + 1.
WHEN 1 OR 2.
MESSAGE lv_exceptionmsg TYPE 'I'.
WRITE: / lv_taskname, ':', lv_exceptionmsg.
WHEN 3.
WAIT FOR ASYNCHRONOUS TASKS UNTIL lv_recvjobs = lv_sentjobs UP TO 300 SECONDS.
lv_retry = ABAP_TRUE.
WHEN OTHERS.
MESSAGE 'Unknown error.' TYPE 'I'.
ENDCASE.
ENDWHILE.
ENDFORM.
FORM RETURN_BAPI_MATERIAL USING TASKNAME.
DATA INFO LIKE RFCSI.
RECEIVE RESULTS FROM FUNCTION 'BAPI_MATERIAL_SAVEREPLICA'
IMPORTING
RFCSI_EXPORT = INFO
RETURNMESSAGES = GT_BAPI_SAVEREPLICA_RETURN.
ENDFORM.
这是转储发生时的堆栈。
为什么函数 ME_INFORECORD_MAINTAIN_MULTI 受到 GUI 会话限制以及如何绕过它?
在某些情况下,功能模块会在内部引发 GUI 会话(“ABAP 会话”)。这是由调用对话框模块的内部处理引起的。
“在 aRFC 处理中调用 dynpro 时,会在 RFC 客户端中打开额外的 ABAP 会话(另请参阅 RFC 对话交互。不能超过 ABAP 会话的最大数量,如果有更多,则会显示错误消息。最大数量会话数在配置文件参数 rdisp/max_alt_modes 中定义,并且不能大于 16。"
https://help.sap.com/doc/abapdocu_750_index_htm/7.50/en-US/abapcall_function_starting.htm
您确定有误吗
“已达到最大 GUI 会话数”
由于函数调用?
CALL FUNCTION 'BAPI_MATERIAL_SAVEREPLICA'
STARTING NEW TASK lv_taskname
DESTINATION IN GROUP DEFAULT
PERFORMING RETURN_BAPI_MATERIAL ON END OF TASK
您是否在调用函数语句中包含了异常?
exceptions resource_failure = 1
others = 2.
当群组中不再有免费资源时,您将收到“resource_failure”异常。 根据您的描述,我预计会出现资源失败错误。
检查您正在使用的服务器组的 Rz12 中的设置。 “启动新任务”(通过 rfc)的功能会检查这些参数设置。 因此,如果服务器“忙”,则调用失败。 这是一个基本的 shell 程序,可用于测试并行代码行为。
REPORT ZPARA.
data t type i.
parameters:
cnt type i default 10000000,
packets type i default 10,
para as checkbox default 'X',
waittime type i default 1,
rfcgroup like rzllitab-classname .
data total type f.
data splits type i.
data mod type i.
data packetsize type i.
data: first type i.
data: last type i.
data: this_last type i.
data: this_split type i.
data: ret_splits type i.
data: act_splits type i.
data: taskname type num8 value 0.
data: begin of task occurs 0,
taskname type num8,
uzeit like sy-uzeit,
wpinfo TYPE WPINFO,
end of task.
data max_pbt_wps type i.
data free_pbt_wps type i.
start-of-selection.
PERFORM classic_version.
form classic_version.
**** TO USE THIS CODE,
* create a parallel(rfc) server group in RZ12.
* create the function decribed below
**************************************************
* set run time res low, so measurement in milli not microsecs.
* we are measure BIG runs
refresh task.
set run time clock resolution low.
get run time field t.
total = 0.
check cnt > 0.
if packets = 0.
packets = 5.
endif.
* splits calculated based on packet size
splits = packets.
PACKETSIZE = cnt div PACKETS.
* is parallel mode selected
if para = 'X'.
* parallel processing MUST be initialized first.
call function 'SPBT_INITIALIZE'
exporting
group_name = rfcgroup
importing
max_pbt_wps = max_pbt_wps
free_pbt_wps = free_pbt_wps
exceptions
invalid_group_name = 1
internal_error = 2
pbt_env_already_initialized = 3
currently_no_resources_avail = 4
no_pbt_resources_found = 5
cant_init_different_pbt_groups = 6
others = 7
.
if sy-subrc <> 0.
* if our group failed or the available processes was 0,
* we would exit cleanly here.
* for the demo, just bomb out.
endif.
last = 0.
ret_splits = 0.
act_splits = 0.
* so for each split
do splits times.
* make a jobname
taskname = taskname + 1.
* work out which chunk we are processing
* ie were are we up to ??
first = last + 1.
this_last = first + packetsize - 1.
* for info purposes record which split
this_split = sy-index.
* just in case we have the last split,
* calculated adjust target end,
if this_last > cnt.
this_last = cnt.
endif.
* try a dispatch this split.
* this is where more logic is needed.
* here we set a max of a hundred tries to dispatch
* something. IN VERY LARGE jobs,
* a commit work and a more intelligent wait
* might be appropriate.
* we at least wait, 1 then 2 then 3... secs etc
* until we get a look in.
do 100 times.
* inside a parallel ( new ) task
* do a chunk of work.
* NO importing parameters here. The result is returned
* in the receiving function.
* SPECIAL, extra, exceptions are available to control
* success or otherwise of the dispatch.
write: / 'Split ', this_split, 'dispatch at', sy-uzeit.
call function 'Z_CHUNK' starting new task taskname
destination in group rfcgroup
performing finished on end of task
exporting
from_int = first
to_int = this_last
exceptions
resource_failure = 1
others = 2.
if sy-subrc = 0.
* dispatch ok, record the fact and march on...
act_splits = act_splits + 1.
last = first + PACKETSIZE - 1.
exit. " the retry until dispatched loop.
else.
write: 'No resource free'.
write: / 'Split ', this_split, 'Waits ', waittime, 'secs at',
sy-uzeit.
* wait x seconds, each attempt waits successlively longer
wait up to waittime seconds.
endif.
enddo.
* Actual failure to dispatch is not captured in this version
* your code should consider this issue.
enddo.
*** THE BIG ROUNDUP
* we wait here until ALL splits are returned.
* we do that by waiting until a return counter
* equals the numbers of dispatches.
* this wait does not wait indefinitely if a dispatch above
* fails, since another continue point is NO oustanding
* async tasks.
***
wait until ret_splits >= act_splits.
else.
call function 'Z_CHUNK'
exporting
from_int = 1
to_int = cnt
importing
tot = total.
endif.
get run time field t.
t = t / 1000.
loop at task.
write: / 'Received task', task-taskname, ' at ', task-uzeit, ' in WP:', task-WPINFO-WP_INDEX.
endloop.
write: / 'Parallel', para.
write: / 'Time ms ', t left-justified.
write: / 'Splits ', splits left-justified.
write: / 'Total ', total left-justified.
endform.
*---------------------------------------------------------------------*
* FORM finished *
*---------------------------------------------------------------------*
* ........ *
*---------------------------------------------------------------------*
* --> TASKNAME *
*---------------------------------------------------------------------*
form finished using taskname.
data: ls_wpinfo type WPINFO.
data l_tot type f.
receive results from function 'Z_CHUNK'
importing
tot = l_tot
wp_index = LS_WPINFO-WP_INDEX.
* when receiving a task back, we get out result
* and record that the task returned, by uping a counter.
task-taskname = taskname.
task-uzeit = sy-uzeit.
task-WPINFO = LS_WPINFO.
append task.
total = total + l_tot.
ret_splits = ret_splits + 1.
endform.
*****
* Create this function to test.
FUNCTION Z_CHUNK
IMPORTING
VALUE(FROM_INT) TYPE I
VALUE(TO_INT) TYPE I
EXPORTING
VALUE(TOT) TYPE F
VALUE(WP_INDEX) TYPE WPINFO-WP_INDEX.
data l_i type i.
tot = 0.
check to_int > from_int.
l_i = from_int.
while l_i <= to_int.
tot = tot + l_i.
l_i = l_i + 1.
endwhile.
CALL FUNCTION 'TH_GET_OWN_WP_NO'
IMPORTING
WP_INDEX = WP_INDEX
.
ENDFUNCTION.