Translate

jueves, 28 de agosto de 2014

Ejemplo Mejorado Proceso Paralelo Modulo de Funciones

En la siguiente entrada se explica como con un cambio de enfoque podemos hacer mucho más eficiente el parallel processing o proceso paralelo con modulo de funciones para así tener más control del mismo y un uso eficiente de la memoria del servidor.

A continuación mostraré un breve ejemplo:

Acá se seleccionan el número de paquetes en el cual se debe distribuir la carga en tu función paralela:
SELECTION-SCREEN BEGIN OF BLOCK b03 WITH FRAME TITLE text-010.
SELECTION-SCREEN SKIP.
SELECT-OPTIONSso_packs for CPETASKLOG-CPEINSTANCEID no INTERVALS.
SELECTION-SCREEN SKIP.
SELECTION-SCREEN END OF BLOCK b03.
Se seleccionan los datos a procesar se hace la llamada al modulo de funciones que se va a ejecutar en paralelo:
START-OF-SELECTION.
PERFORM GET_DATA CHANGING  tab_datos.
Se inicia el proceso previo al proceso paralelo:
PERFORM F_PROCESS_PP USING TAB_DATOS
                                                             GT_REPROCESS.
Toda la información que se almacena en gt_reprocess son registros que no fueron procesados por diferentes razones.
En la próxima entrada indicaremos como proceder a su reprocesamiento
PERFORM SHOW_LOGS USING GT_LOG.

“------------------------------------------------------------------------------------
FORM F_PROCESS_PP  USING tab_reg_datos  like tab_datos
                                         CHANGING  P_REPROCESS LIKE gt_reprocess.
  DATA: lineas TYPE i,
        ii TYPE string,
        lv_msg TYPE string,
        zit_trab  TYPE TABLE OF zbl02_st_datos_trabajador.
****************************************************************
  data : rng_nro TYPE i,
         lv_LINE_from type I,
         lv_LINE_to   type I,
         e_cnt_packages TYPE BANK_DTE_PP_CNT_PACKAGES,
         tabix TYPE sytabix.
  DATA: lv_range type i.
*****************************************************************
  DESCRIBE TABLE tab_reg_datos LINES gv_lineas.
Se asignan el número de paquetes en el cual debemos subdividir el trabajo paralelo.
e_cnt_packages = so_packs-low.
  DO e_cnt_packages  TIMES.
    add 1 to rng_nro .
“Esta function  nos dice el rango de que linea a que linea va cada paquete
    CALL FUNCTION 'ZMF_FILE_PACK_RANGE'
      EXPORTING
        I_RANGE_NO         = rng_nro
        I_CNT_RANGES_TOTAL = e_cnt_packages
        I_START_NUM        = 1
        I_LAST_NUM         = gv_lineas
      IMPORTING
        E_LINE_FROM        = lv_LINE_from
        E_LINE_TO          = lv_LINE_to
      EXCEPTIONS
        RANGE_INVALID      = 1
        OTHERS             = 2.
    IF SY-SUBRC <> 0.
* Implement suitable error handling here
    ENDIF.
·         Agregamos el numero de lineas a una nueva table para su procesamiento paralelo
    APPEND LINES OF tab_reg_trab FROM lv_line_from TO lv_line_to TO TAB_DATOS.
*
Aca llamamos a nuestra función que se desarrollo en la entrada anterior con nuevos parámetros
    PERFORM CALL_PARALLEL USING TAB_DATOS
                                                                  rng_nro
                                           CHANGING  P_REPROCESS.
    free TAB_DATOS[].
  ENDDO.
* Se hace esperar a la tarea para que se ejecute correctamente.
  WAIT UNTIL gv_rcv_jobs >= gv_snd_jobs.
ENDFORM.                    " F_PROCESS_PP

FORM f_procesar_reg USING    tab_datos LIKE tab_datos
                                                       task TYPE i
                                      CHANGING  tab_reprocess LIKE gt_reprocess.
  DATA: lv_msg TYPE string,
        modul TYPE i,
        wa_reprocess TYPE ty_tasks.
  "Fecha para mostrar el log
  CONCATENATE sy-datum+6(2)
              sy-datum+4(2)
              sy-datum(4)
         INTO gv_fecha
  SEPARATED BY gc_punto.
*
  CLEAR gs_reg_trab.
  gv_system = text-003.
* Se obtiene el índice para generar el nombre de la tarea.
  gv_index = task.
  CONDENSE gv_index.
* Se genera el nombre de la tarea, único por cada registro a procesar.
  CONCATENATE text-006
              gv_index
         INTO gv_taskname.
* Se llama el RFC
  CALL FUNCTION 'ZBL02_FM_PROC_DAT_TRAB' STARTING NEW TASK gv_taskname
    DESTINATION IN GROUP gv_system
    PERFORMING f_finalizar_funcion ON END OF TASK
    EXPORTING
      it_str_datos_trab     = tab_datos
    EXCEPTIONS
      system_failure        = 1  MESSAGE mess
      communication_failure = 2  MESSAGE mess
      resource_failure      = 3.      "Tipo de relación
  CASE sy-subrc.
    WHEN 0. "Si no hay error se incrementa contador de éxito.
      gv_snd_jobs = gv_snd_jobs + 1.
    WHEN 1 or 2.
      MESSAGE mess TYPE 'I'.
    WHEN 3. "Si hubo error se hace esperar a la tarea.
      IF  gv_snd_jobs >= 1 AND gv_exc_flag = 0.
        gv_exc_flag = 1.
        WAIT UNTIL gv_rcv_jobs >= gv_snd_jobs
        UP TO 5 SECONDS.
      ENDIF.
      IF sy-subrc = 0.
        gv_exc_flag = 0.
      ELSE.
        MESSAGE 'Resource failure' TYPE 'I'.
      ENDIF.
      wa_reprocess-taskname = gv_taskname.
      wa_reprocess-tasknro  = task.
      APPEND wa_reprocess to tab_reprocess
“Aca guardamos solo la tarea que fallo para su porterior reprocesamiento
      free: lv_msg,wa_reprocess.
    WHEN OTHERS.
      MESSAGE 'Other Error' TYPE 'I'.
  ENDCASE.
*
ENDFORM.                    
Una vez finalizado todos los llamados a la función paralela el programa llama al perform donde recibimos el resultado de su ejecución y guardamos los logs correspondientes.
FORM f_finalizar_funcion USING gv_taskname.
  DATA: mess  TYPE c LENGTH 80.
  task_wa-name = gv_taskname.
  gv_rcv_jobs = gv_rcv_jobs + 1.
* Se reciben los resultados del RFC para loguear los mensajes.
  RECEIVE RESULTS FROM FUNCTION ' Z_FM_PARALLELS '
   TABLES
    e_tab_return = gt_log
“Es importante colocar las exceptions en caso de algún error de comunicación o el paralelo tenga “algún problema
  EXCEPTIONS
      system_failure        = 1 MESSAGE mess
      communication_failure = 2 MESSAGE mess .
  IF sy-subrc eq 0.
    task_wa-dest = info-rfcdest.
  ELSE.
    task_wa-dest = mess.
  ENDIF.
  APPEND task_wa TO task_list.
*
* Se loguean todos los mensajes
  CLEAR gs_log.
  LOOP AT gt_log INTO gs_log.
    CLEAR gv_tam_msj.
    gv_tam_msj = strlen( gs_log-message ).
    IF gv_tam_msj > 50.
      gs_message-msg_text_2 = gs_log-message+50.
      IF gv_tam_msj > 100.
        gs_message-msg_text_3 = gs_log-message+100.
      ENDIF.
    ENDIF.
    gs_message-msgty      = gs_log-type.
    gs_message-msg_text_1 = gs_log-message.
    APPEND gs_message TO gt_message.
    CLEAR: gs_message.
*           gt_message[].
    CLEAR gs_log.
*
  ENDLOOP.
  FREE: gt_log.
*
ENDFORM.


·         Los puntos relevantes del código se han puesto en negrita para facilitar su importancia

No hay comentarios.:

Publicar un comentario