Remote Function Call (RFC) - стандартный интерфейс связи между SAP системами. RFC функцию можно выполнить в другой системе.
Существует несколько видов RFC функций.
sRFC
sRFC - синхронные RFC. Данный вид RFC выполняется на принципах синхронной связи. Т.е. целевая система должна быть доступна в данный момент, а система из которой вызывается RFC ожидает выполнения. Применение данных RFC целесообразно когда требуется получить данные из целевой системы. Например, при работе в ERP требуется чтение данных какой-либо таблицы в HR системе.
ФМ должен иметь тип выполнения - "Дистанционный модуль".
Используется следующий синтаксис:
CALL FUNCTION func_name DESTINATION dest parameter list.
Где dest - имя RFC соединения (транзакция SM59). Такжe вместо можно указать
- 'NONE' - Произойдет вызов модуля в текущей системе, но в отдельном LUW.
- 'BACK' - Дополнение используется в вызванном RFC модуле для выполнения ФМ в вызывающей системе. Своеобразный сон во сне. Злоупотреблять не стоит, т.к. отладка потом взрывает мозг.
Пример вызова:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
CALL FUNCTION 'RFC_READ_TABLE' DESTINATION 'TEST_HRSYS100' EXPORTING query_table = 'DEVACCESS' delimiter = ' ' TABLES options = lt_options fields = lt_fields data = lt_data EXCEPTIONS table_not_available = 1 table_without_data = 2 option_not_valid = 3 field_not_valid = 4 not_authorized = 5 data_buffer_exceeded = 6 OTHERS = 7. IF sy-subrc <> 0. * Implement suitable error handling here ENDIF. |
aRFC
aRFC - асинхронные RFC. Если придираться к терминологии, то асинхронные RFC в сапе не асинхронны в полной мере. Их асинхронность по большому счету только в том, что программа может не ждать их выполнения. В остальном это те же самые синхронные RFC, т.к. система должна быть доступна при их запуске.
Используется следующий синтаксис для вызова:
1 2 3 4 5 |
CALL FUNCTION Remotefunction STARTING NEW TASK Taskname DESTINATION ... EXPORTING... TABLES ... EXCEPTIONS... |
Т.к. работа происходит асинхронно, получение данных отличается от обычного ФМ. При вызове следует указать подпрограмму или метод вызываемый по завершению функционального модуля. Существует дополнение RECEIVE RESULTS FROM FUNCTION для получения данных из выполненного ФМ
Пример синтаксиса:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
DATA: gv_end1, gv_end2, gv_result type i. FORM rfc_results USING taskname. DATA lv_res TYPE i. CASE taskname. WHEN 'Z_ARFC1'. gv_flag1 = abap_true. WHEN 'Z_ARFC2'. gv_flag2 = abap_true. ENDCASE. " Обязательно необходимо вызвать получение результата работы aRFC RECEIVE RESULTS FROM FUNCTION 'ZZ_ARFC_TEST' IMPORTING result = lv_res "Вот здесь мы и получаем данные EXCEPTIONS system_failure = 1 wrong_input = 2. gv_result = gv_result + lv_res ENDFORM. CALL FUNCTION 'ZZ_ARFC_TEST' STARTING NEW TASK 'Z_ARFC1' PERFORMING rfc_results ON END OF TASK EXPORTING count = 1 EXCEPTIONS communication_failure = 1 system_failure = 2 resource_failure = 3. . CALL FUNCTION 'ZZ_ARFC_TEST' STARTING NEW TASK 'Z_ARFC2' PERFORMING rfc_results ON END OF TASK EXPORTING count = 2 EXCEPTIONS communication_failure = 1 system_failure = 2 resource_failure = 3. WAIT UNTIL gv_end1 = abap_true AND gv_end2 = abap_true. IF sy-subrc = 0. "... ELSE. "... ENDIF. |
Сам ФМ имеет такую структуру:
1 2 3 4 5 6 7 8 9 10 11 12 |
FUNCTION ZZ_ARFC_TEST. *"---------------------------------------------------------------------- *"*"Локальный интерфейс: *" IMPORTING *" VALUE(COUNT) TYPE I *" EXPORTING *" VALUE(RESULT) TYPE I *"---------------------------------------------------------------------- "some code result = ... ENDFUNCTION. |
дополнение PERFORMING rfc_results ON END OF TASK означает, что подпрограмма rfc_results будет вызвана после выполнения каждого из ФМ.
Вместо дополнения PERFORMING ... ON END OF TASK можно использовать CALLING method ON END OF TASK для указания метода.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
CLASS lcl_rfc_call DEFINITION. PUBLIC SECTION. CLASS-METHODS: rfc_response IMPORTING p_task TYPE clike. CLASS-DATA: mv_result TYPE i. ENDCLASS. CLASS lcl_rfc_call IMPLEMENTATION. METHOD rfc_response. DATA lv_result TYPE i. RECEIVE RESULTS FROM FUNCTION 'ZZ_ARFC_TEST' IMPORTING result = lv_result EXCEPTIONS system_failure = 1 wrong_input = 2. mv_result = mv_result + lv_result. ENDMETHOD. ENDCLASS. CALL FUNCTION 'ZZ_ARFC_TEST' DESTINATION 'NONE' STARTING NEW TASK 'Z_TASK' CALLING lcl_rfc_call=>rfc_response ON END OF TASK EXPORTING iv_num = 1 EXCEPTIONS communication_failure = 1 system_failure = 2. |
Распараллеливание при помощи aRFC
Дополнение DESTINATION IN GROUP <group name> позволяет запускать RFC в группе (настройка групп производится в транзакции RZ12). При указании SPACE или DEFAULT группа будет выбрана автоматически. Перед запуском RFC необходимо проинициализировать группу ФМ-ом 'SPBT_INITIALIZE' он покажет общее количество процессов и число доступных на данный момент.
Приведу пример программы из документации, все достаточно понятно, единственное, что в реальной задаче стоит подумать об ограничении максимального количества занимаемых процессов, чтобы не занять все.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 |
* DATA: group LIKE rzllitab-classname VALUE ' ', "Parallel processing group. "SPACE = group default (all "servers) wp_available TYPE i, "Number of dialog work processes "available for parallel processing "(free work processes) wp_total TYPE i, "Total number of dialog work "processes in the group msg(80) VALUE space, "Container for error message in "case of remote RFC exception. info LIKE rfcsi, c, "Message text jobs TYPE i VALUE 10, "Number of parallel jobs snd_jobs TYPE i VALUE 1, "Work packets sent for processing rcv_jobs TYPE i VALUE 1, "Work packet replies received excp_flag(1) TYPE c, "Number of RESOURCE_FAILUREs taskname(4) TYPE n VALUE '0001', "Task name (name of "parallel processing work unit) BEGIN OF tasklist OCCURS 10, "Task administration taskname(4) TYPE c, rfcdest LIKE rfcsi-rfcdest, rfchost LIKE rfcsi-rfchost, END OF tasklist. * * Optional call to SBPT_INITIALIZE to check the * group in which parallel processing is to take place. * Could be used to optimize sizing of work packets * work / WP_AVAILABLE). * CALL FUNCTION 'SPBT_INITIALIZE' EXPORTING group_name = group "Name of group to check IMPORTING max_pbt_wps = wp_total "Total number of dialog work "processes available in group "for parallel processing free_pbt_wps = wp_available "Number of work processes "available in group for "parallel processing at this "moment EXCEPTIONS invalid_group_name = 1 "Incorrect group name; RFC "group not defined. See "transaction RZ12 internal_error = 2 "SAP system error; see the "system log (transaction "SM21) for diagnostic info pbt_env_already_initialized = 3 "Function module may be "called only once; is called "automatically by the SAP system if you "do not call before starting "parallel processing currently_no_resources_avail = 4 "No dialog work processes "in the group are available; "they are busy or server load "is too high no_pbt_resources_found = 5 "No servers in the group "met the criteria of > "two work processes "defined. cant_init_different_pbt_groups = 6 "You have already initialized "one group and have now tried "initialize a different group. OTHERS = 7. CASE sy-subrc. WHEN 0. "Everything's ok. Optionally set up for optimizing size of "work packets. WHEN 1. "Non-existent group name. Stop report. MESSAGE e836. "Group not defined. WHEN 2. "System error. Stop and check system log for error "analysis. WHEN 3. "Programming error. Stop and correct program. MESSAGE e833. "PBT environment was already initialized. WHEN 4. "No resources: this may be a temporary problem. You "may wish to pause briefly and repeat the call. Otherwise "check your RFC group administration: Group defined "in accordance with your requirements? MESSAGE e837. "All servers currently busy. WHEN 5. "Check your servers, network, operation modes. WHEN 6. * Do parallel processing. Use CALL FUNCTION STARTING NEW TASK * DESTINATION IN GROUP to call the function module that does the * work. Make a call for each record that is to be processed, or * divide the records into work packets. In each case, provide the * set of records as an internal table in the CALL FUNCTION * keyword (EXPORT, TABLES arguments). DO. CALL FUNCTION 'RFC_SYSTEM_INFO' "Function module to perform "in parallel STARTING NEW TASK taskname "Name for identifying this "RFC call DESTINATION IN GROUP group "Name of group of servers to "use for parallel processing. "Enter group name exactly "as it appears in transaction "RZ12 (all caps). You may "use only one group name in a "particular ABAP program. PERFORMING return_info ON END OF TASK "This form is called when the "RFC call completes. It can "collect IMPORT and TABLES "parameters from the called "function with RECEIVE. EXCEPTIONS communication_failure = 1 MESSAGE msg "Destination server not "reached or communication "interrupted. MESSAGE msg "captures any message "returned with this "exception (E or A messages "from the called FM, for "example. After exception "1 or 2, instead of aborting "your program, you could use "SPBT_GET_PP_DESTINATION and "SPBT_DO_NOT_USE_SERVER to "exclude this server from "further parallel processing. "You could then re-try this "call using a different "server. system_failure = 2 MESSAGE msg "Program or other internal "SAP error. MESSAGE msg "captures any message "returned with this "exception. resource_failure = 3. "No work processes are "currently available. Your "program MUST handle this "exception. your_exceptions = x. "Add exceptions generated by "the called function module "here. Exceptions are "returned to you and you can "respond to them here. CASE sy-subrc. WHEN 0. "Administration of asynchronous RFC tasks "Save name of task... tasklist-taskname = taskname. "... and get server that is performing RFC call. CALL FUNCTION 'SPBT_GET_PP_DESTINATION' EXPORTING rfcdest = tasklist-rfcdest EXCEPTIONS OTHERS = 1. APPEND tasklist. WRITE: / 'Started task: ', tasklist-taskname COLOR 2. taskname = taskname + 1. snd_jobs = snd_jobs + 1. "Mechanism for determining when to leave the loop. Here, a "simple counter of the number of parallel processing tasks. "In production use, you would end the loop when you have "finished dispatching the data that is to be processed. jobs = jobs - 1. "Number of existing jobs IF jobs = 0. EXIT. "Job processing finished ENDIF. WHEN 1 OR 2. "Handle communication and system failure. Your program must "catch these exceptions and arrange for a recoverable "termination of the background processing job. "Recommendation: Log the data that has been processed when "an RFC task is started and when it returns, so that the "job can be restarted with unprocessed data. WRITE msg. "Remove server from further consideration for "parallel processing tasks in this program. "Get name of server just called... CALL FUNCTION 'SPBT_GET_PP_DESTINATION' EXPORTING rfcdest = tasklist-rfcdest EXCEPTIONS OTHERS = 1. "Then remove from list of available servers. CALL FUNCTION 'SPBT_DO_NOT_USE_SERVER' IMPORTING servername = tasklist-rfcdest EXCEPTIONS invalid_server_name = 1 no_more_resources_left = 2 "No servers left in group. pbt_env_not_initialized_yet = 3 OTHERS = 4. WHEN 3. "No resources (dialog work processes) available at "present. You need to handle this exception, waiting "and repeating the CALL FUNCTION until processing "can continue or it is apparent that there is a "problem that prevents continuation. MESSAGE i837. "All servers currently busy. "Wait for replies to asynchronous RFC calls. Each "reply should make a dialog work process available again. IF excp_flag = space. excp_flag = 'X'. "First attempt at RESOURCE_FAILURE handling. Wait "until all RFC calls have returned or up to 1 second. "Then repeat CALL FUNCTION. WAIT UNTIL rcv_jobs >= snd_jobs UP TO '1' SECONDS. ELSE. "Second attempt at RESOURCE_FAILURE handling WAIT UNTIL rcv_jobs >= snd_jobs UP TO '5' SECONDS. "SY-SUBRC 0 from WAIT shows that replies have returned. "The resource problem was therefore probably temporary "and due to the workload. A non-zero RC suggests that "no RFC calls have been completed, and there may be "problems. IF sy-subrc = 0. CLEAR excp_flag. ELSE. "No replies "Endless loop handling ... ENDIF. ENDIF. ENDCASE. ENDDO. ... * * Wait for end of job: replies from all RFC tasks. * Receive remaining asynchronous replies WAIT UNTIL rcv_jobs >= snd_jobs. LOOP AT tasklist. WRITE:/ 'Received task:', tasklist-taskname COLOR 1, 30 'Destination: ', tasklist-rfcdest COLOR 1. ENDLOOP. ... * * This routine is triggered when an RFC call completes and * returns. The routine uses RECEIVE to collect IMPORT and TABLE * data from the RFC function module. * * Note that the WRITE keyword is not supported in asynchronous * RFC. If you need to generate a list, then your RFC function * module should return the list data in an internal table. You * can then collect this data and output the list at the conclusion * of processing. * FORM return_info USING taskname. DATA: info_rfcdest LIKE tasklist-rfcdest. RECEIVE RESULTS FROM FUNCTION 'RFC_SYSTEM_INFO' IMPORTING rfcsi_export = info EXCEPTIONS communication_failure = 1 system_failure = 2. rcv_jobs = rcv_jobs + 1. "Receiving data IF sy-subrc NE 0. * handle communication and system failure ... ELSE. READ TABLE tasklist WITH KEY taskname = taskname. IF sy-subrc = 0. "Register data tasklist-rfchost = info_rfchost. MODIFY tasklist INDEX sy-tabix. ENDIF. ENDIF. ... ENDFORM |
Хотя, если уж говорить о реальных задачах распараллеливания, стоит посмотреть в сторону SPTA_PARA_PROCESS_START_2 или поддержать отечественного производителя c его zconcurrency_api.
tRFC
tRFC - транзакционные RFC. Настоящие асинхронные RFC, которые позволяют вызывать RFC при недоступной системе выполнения RFC. tRFC сохраняет вызываемую функцию с соответствующими параметрами в базе данных под уникальным идентификатором транзакции (TID)
Если вызов отправлен, а принимающая система не работает, вызов остается в локальной очереди до более позднего времени. Вызывающая программа может продолжать работу, не дожидаясь отклика от вызванного ФМ. Если принимающая система не становится активной в течение определенного периода времени, вызов планируется в пакетном режиме.
tRFC запускаются в одном LUW, т.е. случае ошибки происходит откат для всех ФМ.
Получить результат выполнения подобных ФМ напрямую как в случае c aRFC или sRFC невозможно.
tRFC вызываются при помощи дополнения IN BACKGROUND TASK и будут отработаны после оператора COMMIT WORK. Для запуска tRFC до COMMIT WORK можно использовать ФМ START_OF_BACKGROUNDTASK.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
CALL FUNCTION 'ZZ_RFC_TEST' IN BACKGROUND TASK DESTINATION 'NONE' AS SEPARATE UNIT EXPORTING iv_num = 1. CALL FUNCTION 'ZZ_RFC_TEST' IN BACKGROUND TASK DESTINATION 'NONE' AS SEPARATE UNIT EXPORTING iv_num = 2. CALL FUNCTION 'ZZ_RFC_TEST' IN BACKGROUND TASK DESTINATION 'NONE' AS SEPARATE UNIT EXPORTING iv_num = 3. CALL FUNCTION 'ZZ_RFC_TEST' IN BACKGROUND TASK DESTINATION 'NONE' AS SEPARATE UNIT EXPORTING iv_num = 4. COMMIT WORK. |
Мониторинг производится в транзакции SM58
AS SEPARATE UNIT - дополнение позволяет выполнять каждый вызов в отдельном контексте. По умолчанию все вызовы функций имеют общий контекст. Т.е., например, если вы укажете в группе функций глобальную переменную gv_test, значение которое вы туда положите во время выполнения функции, можно будет увидеть и изменить в следующих. AS SEPARATE UNIT позволяет избежать подобного взаимного влияния.
qRFC - разновидность tRFC, позволяющая реализовывать очередь с последовательным вызовом ФМ. В отличие от tRFC выполняются в последовательности вызова(tRFC это не гарантируют);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
CALL FUNCTION 'TRFC_SET_QUEUE_NAME' EXPORTING qname = 'QUEUE1' "Задаем имя очереди EXCEPTIONS invalid_queue_name = 1 OTHERS = 2. IF sy-subrc <> 0. * Implement suitable error handling here ENDIF. CALL FUNCTION 'ZZ_RFC_TEST' IN BACKGROUND TASK DESTINATION 'NONE'. CALL FUNCTION 'ZZ_RFC_TEST' IN BACKGROUND TASK DESTINATION 'NONE'. CALL FUNCTION 'ZZ_RFC_TEST' IN BACKGROUND TASK DESTINATION 'NONE'. CALL FUNCTION 'ZZ_RFC_TEST' IN BACKGROUND TASK DESTINATION 'NONE'. COMMIT WORK. |
Мониторинг можно производить в транзакции SQ01
При возникновении исключительной ситуации в одном из модулей, выполнение очереди будет остановлено. Можно вручную сделать рестарт всей очереди.
bgRFC - фоновые RFC.
Обновленные tRFC и qRFC, которые SAP рекомендует использовать вместо классических. Создаются на основе интерфейса IF_BGRFC_UNIT.
Отладка RFC
Для отладки RFC надо поставить внешнюю точку прерывания под пользователем который указан в настройках RFC соединения или текущим, если оно предполагает использование данных текущего пользователя.
В верхнем меню выбираем Утилиты->Параметры настройки->ABAP редактор->Отладка
“…если уж говорить о реальных задачах распараллеливания, стоит посмотреть в сторону SPTA_PARA_PROCESS_START_2 или поддержать отечественного производителя c его zconcurrency_api.“
Спасибо за ссылку, история тебя не забудет