ABAP /

Vigilante de JOBS con envio de Mail

El programa ZINI_JOB_WATCHERS es una herramienta de monitorización de jobs de fondo (BTC) desarrollada en ABAP OOP. A través de su pantalla de selección recibe el nombre del job a vigilar (que admite comodines como * y +), opcionalmente su número, un rango de fechas, los minutos de espera entre reintentos (por defecto 5) y la dirección de correo de destino. El programa funciona en dos modos según cómo se ejecute: en modo online (ejecución interactiva por un usuario) consulta los jobs que están actualmente activos y que coinciden con el nombre y el rango de fechas, los muestra en un listado ALV emergente para que el usuario seleccione uno, y a partir de esa elección programa automáticamente un nuevo job que relanza este mismo programa pasándole los parámetros y el número del job seleccionado. De este modo, la vigilancia continúa de forma desatendida en segundo plano.

En modo fondo (cuando el programa se ejecuta como job) comprueba si el job monitorizado sigue en estado activo. Si todavía se está ejecutando, el programa se reprograma a sí mismo para volver a comprobarlo pasados los minutos indicados (controlando correctamente el cambio de día mediante timestamps) y finaliza, repitiendo ese ciclo hasta que el job termine. Cuando detecta que el job ya ha finalizado, envía un correo electrónico informativo mediante la clase zini_cl_email, cuyo asunto es el nombre del job y cuyo cuerpo incluye el mensaje "El job ha finalizado" junto con el estado final traducido a texto legible, la máquina (servidor) donde se ejecutó, el mandante y las horas de inicio y fin. Para garantizar que este aviso llegue de inmediato y no quede retenido en la cola de la transacción SOST, el envío se marca como inmediato afectando únicamente a ese correo concreto.

Requiere la clase de envio de correos

  1.  
  2. *&---------------------------------------------------------------------*
  3. *& Report ZINI_JOB_WATCHERS
  4. *&---------------------------------------------------------------------*
  5. *& Monitor de JOBs:
  6. *&   - Online: lista los jobs activos que coinciden con el nombre y el
  7. *&             rango de fechas. El usuario selecciona uno y se programa
  8. *&             un job que vuelve a ejecutar este mismo programa con el
  9. *&             numero de job elegido.
  10. *&   - Fondo : comprueba si el job indicado sigue activo. Si lo esta, se
  11. *&             reprograma a si mismo 5 minutos despues. Si no, envia un
  12. *&             correo informando del estado final del job.
  13. *&---------------------------------------------------------------------*
  14. REPORT ZINI_JOB_WATCHERS.
  15.  
  16. *--[ Include con la clase de envio de correo (zini_cl_email)
  17. INCLUDE zini_i_email. "https://wiki.bergonzini.com/pmwiki.php?n=ABAP.SSENDMAIL
  18.  
  19. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  20. *--[ Pantalla de seleccion
  21. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  22. SELECTION-SCREEN BEGIN OF BLOCK b1 WITH FRAME TITLE TEXT-t01.
  23.   PARAMETERS     p_job  TYPE btcjob    OBLIGATORY.   " Nombre del job
  24.   PARAMETERS     p_jobn TYPE btcjobcnt.              " Numero del job
  25.   SELECT-OPTIONS s_fecha FOR sy-datum.               " Rango de fechas
  26.   "Minutos de espera para reprogramar el job en fondo (por defecto 5)
  27.   PARAMETERS     p_delay TYPE i DEFAULT 5 OBLIGATORY. " Retardo (minutos)
  28.   "Nota: los PARAMETERS no admiten el tipo STRING; se usa AD_SMTPADR,
  29.   "      el tipo estandar para direcciones de correo, y se convierte a
  30.   "      string al utilizar la clase de email.
  31.   PARAMETERS     p_email TYPE ad_smtpadr OBLIGATORY LOWER CASE. " Destino
  32. SELECTION-SCREEN END OF BLOCK b1.
  33.  
  34. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  35. *--[ Ajuste dinamico de la pantalla de seleccion
  36. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  37. AT SELECTION-SCREEN OUTPUT.
  38.  
  39.   "El numero de job (p_jobn) solo tiene sentido en ejecucion de fondo,
  40.   "donde se monitoriza un job concreto. En online el usuario elige el
  41.   "job del listado, por lo que ocultamos el campo.
  42.   LOOP AT SCREEN INTO DATA(ls_screen).
  43.     IF ls_screen-name cp  '*P_JOBN*' AND sy-batch <> abap_true.
  44.       ls_screen-active = 0.          " Ocultar el campo
  45.       MODIFY SCREEN FROM ls_screen.
  46.     ENDIF.
  47.   ENDLOOP.
  48.  
  49.  
  50. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  51. *--[ Definicion de la clase monitor
  52. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  53. CLASS lcl_monitor DEFINITION FINAL.
  54.  
  55.   PUBLIC SECTION.
  56.  
  57.     TYPES tt_jobs TYPE STANDARD TABLE OF tbtco WITH DEFAULT KEY.
  58.  
  59.     "! Constructor: recibe los parametros de entrada del programa
  60.     METHODS constructor
  61.       IMPORTING i_job   TYPE btcjob
  62.                 i_jobn  TYPE btcjobcnt
  63.                 i_email TYPE ad_smtpadr
  64.                 i_delay TYPE i.
  65.  
  66.     "! Punto de entrada: decide el modo de ejecucion (online / fondo)
  67.     METHODS ejecutar.
  68.  
  69.   PRIVATE SECTION.
  70.  
  71.     CONSTANTS:
  72.       c_status_activo TYPE btcstatus VALUE 'R',                 " Job en ejecucion
  73.       c_report        TYPE sy-repid  VALUE 'ZAG3_PRG_TOOL_000'. " Nombre del programa/job
  74.  
  75.     DATA:
  76.       g_job      TYPE btcjob,     " Nombre del job a monitorizar
  77.       g_jobn     TYPE btcjobcnt,  " Numero del job a monitorizar
  78.       g_email    TYPE ad_smtpadr, " Direccion de correo destino
  79.       g_delay    TYPE i,          " Retardo (minutos) para reprogramar
  80.       g_sel_jobname TYPE btcjob,     " Nombre del job seleccionado (online)
  81.       g_sel_jobn TYPE btcjobcnt.  " Numero del job seleccionado (online)
  82.  
  83.     "! Ejecucion interactiva: lista, selecciona y planifica
  84.     METHODS ejecutar_online.
  85.  
  86.     "! Ejecucion en fondo: comprueba estado y reprograma o avisa
  87.     METHODS ejecutar_fondo.
  88.  
  89.     "! Devuelve los jobs activos que cumplen nombre y rango de fechas
  90.     METHODS leer_jobs_activos
  91.       RETURNING VALUE(r_jobs) TYPE tt_jobs.
  92.  
  93.     "! Muestra el listado en ALV y guarda el job seleccionado
  94.     METHODS mostrar_y_seleccionar
  95.       IMPORTING i_jobs TYPE tt_jobs.
  96.  
  97.     "! Programa un nuevo job que relanza este programa
  98.     METHODS planificar_job
  99.       IMPORTING i_job   TYPE btcjob
  100.                 i_jobn  TYPE btcjobcnt
  101.                 i_fecha TYPE sy-datum
  102.                 i_hora  TYPE sy-uzeit.
  103.  
  104.     "! Indica si el job sigue activo
  105.     METHODS job_activo
  106.       IMPORTING i_job           TYPE btcjob
  107.                 i_jobn          TYPE btcjobcnt
  108.       RETURNING VALUE(r_activo) TYPE abap_bool.
  109.  
  110.     "! Lee los datos de cabecera del job
  111.     METHODS leer_datos_job
  112.       IMPORTING i_job        TYPE btcjob
  113.                 i_jobn       TYPE btcjobcnt
  114.       RETURNING VALUE(r_job) TYPE tbtco.
  115.  
  116.     "! Envia el correo de finalizacion del job
  117.     METHODS enviar_email
  118.       IMPORTING i_job TYPE tbtco.
  119.  
  120.     "! Traduce el codigo de estado del job a texto legible
  121.     METHODS texto_estado
  122.       IMPORTING i_status       TYPE btcstatus
  123.       RETURNING VALUE(r_texto) TYPE string.
  124.  
  125. ENDCLASS.
  126.  
  127. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  128. *--[ Implementacion de la clase monitor
  129. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  130. CLASS lcl_monitor IMPLEMENTATION.
  131.  
  132.   METHOD constructor.
  133.     g_job   = i_job.
  134.     g_jobn  = i_jobn.
  135.     g_email = i_email.
  136.     g_delay = i_delay.
  137.   ENDMETHOD.
  138.  
  139.   METHOD ejecutar.
  140.     "sy-batch = 'X' cuando el programa se ejecuta en fondo
  141.     IF sy-batch = abap_true.
  142.       ejecutar_fondo( ).
  143.     ELSE.
  144.       ejecutar_online( ).
  145.     ENDIF.
  146.   ENDMETHOD.
  147.  
  148.   METHOD ejecutar_online.
  149.  
  150.     "1) Obtener los jobs activos que cumplen los filtros
  151.     DATA(lt_jobs) = leer_jobs_activos( ).
  152.  
  153.     IF lt_jobs IS INITIAL.
  154.       MESSAGE 'No existen jobs activos para el nombre y fechas indicados' TYPE 'S'.
  155.       RETURN.
  156.     ENDIF.
  157.  
  158.     "2) Mostrar el listado y recoger la seleccion del usuario
  159.     mostrar_y_seleccionar( lt_jobs ).
  160.  
  161.     IF g_sel_jobn IS INITIAL.
  162.       RETURN. "El usuario no ha seleccionado ningun job
  163.     ENDIF.
  164.  
  165.     "3) Programar un job que relanza este programa con el job elegido
  166.     "   (inicio inmediato)
  167.     planificar_job( i_job   = g_sel_jobname
  168.                     i_jobn  = g_sel_jobn
  169.                     i_fecha = sy-datum
  170.                     i_hora  = sy-uzeit ).
  171.  
  172.     MESSAGE |Monitorizacion programada para el job { g_job } / { g_sel_jobn }| TYPE 'S'.
  173.  
  174.   ENDMETHOD.
  175.  
  176.   METHOD ejecutar_fondo.
  177.  
  178.     "1) Comprobar si el job sigue activo
  179.     IF job_activo( i_job = g_job i_jobn = g_jobn ) = abap_true.
  180.  
  181.       "2a) Sigue activo: reprogramar este programa 5 minutos despues
  182.       DATA lv_fecha TYPE sy-datum.
  183.       DATA lv_hora  TYPE sy-uzeit.
  184.       DATA lv_stamp TYPE timestamp.
  185.  
  186.       GET TIME STAMP FIELD lv_stamp.
  187.       "Sumamos el retardo de forma segura (controla el cambio de dia)
  188.       lv_stamp = cl_abap_tstmp=>add( tstmp = lv_stamp
  189.                                      secs  = g_delay * 60 ).
  190.       CONVERT TIME STAMP lv_stamp TIME ZONE sy-zonlo
  191.               INTO DATE lv_fecha TIME lv_hora.
  192.  
  193.       planificar_job( i_job   = g_job
  194.                       i_jobn  = g_jobn
  195.                       i_fecha = lv_fecha
  196.                       i_hora  = lv_hora ).
  197.  
  198.     ELSE.
  199.  
  200.       "2b) Ha finalizado: enviar correo con el estado final
  201.       enviar_email( leer_datos_job( i_job = g_job i_jobn = g_jobn ) ).
  202.  
  203.     ENDIF.
  204.  
  205.   ENDMETHOD.
  206.  
  207.   METHOD leer_jobs_activos.
  208.  
  209.     "El nombre del job puede contener comodines. Traducimos los
  210.     "comodines habituales de SAP (* y +) a los de SQL (% y _) para
  211.     "poder usar el operador LIKE en la consulta.
  212.     DATA(lv_pattern) = g_job.
  213.     REPLACE ALL OCCURRENCES OF '*' IN lv_pattern WITH '%'.
  214.     REPLACE ALL OCCURRENCES OF '+' IN lv_pattern WITH '_'.
  215.  
  216.     "Jobs en ejecucion que coinciden con el patron de nombre y el
  217.     "rango de fechas
  218.     SELECT * FROM tbtco
  219.       INTO TABLE @r_jobs
  220.       WHERE jobname LIKE @lv_pattern
  221.         AND status  = @c_status_activo
  222.         AND sdldate IN @s_fecha
  223.       ORDER BY sdldate DESCENDING, sdltime DESCENDING.
  224.  
  225.   ENDMETHOD.
  226.  
  227.   METHOD mostrar_y_seleccionar.
  228.  
  229.     DATA(lt_jobs) = i_jobs. "Copia local editable para el ALV
  230.  
  231.     "Construir el ALV en modo popup
  232.     TRY.
  233.         cl_salv_table=>factory(
  234.           IMPORTING r_salv_table = DATA(lo_alv)
  235.           CHANGING  t_table      = lt_jobs ).
  236.       CATCH cx_salv_msg INTO DATA(lx_salv).
  237.         MESSAGE lx_salv->get_text( ) TYPE 'S'.
  238.         RETURN.
  239.     ENDTRY.
  240.  
  241.     "Activar funciones y seleccion de una unica fila
  242.     lo_alv->get_functions( )->set_all( ).
  243.     lo_alv->get_columns( )->set_optimize( ).
  244.  
  245.     DATA(lo_sel) = lo_alv->get_selections( ).
  246.     lo_sel->set_selection_mode( if_salv_c_selection_mode=>single ).
  247.  
  248.     lo_alv->set_screen_popup( start_column = 5
  249.                               end_column   = 120
  250.                               start_line   = 2
  251.                               end_line     = 20 ).
  252.     lo_alv->display( ).
  253.  
  254.     "Recoger la fila seleccionada tras cerrar el popup
  255.     DATA(lt_rows) = lo_sel->get_selected_rows( ).
  256.  
  257.     IF lt_rows IS INITIAL.
  258.       MESSAGE 'No se ha seleccionado ningun job' TYPE 'S'.
  259.       RETURN.
  260.     ENDIF.
  261.  
  262.     READ TABLE lt_jobs INTO DATA(ls_job) INDEX lt_rows[ 1 ].
  263.     IF sy-subrc = 0.
  264.       g_sel_jobn = ls_job-jobcount.
  265.       g_sel_jobname = ls_job-jobname.
  266.     ENDIF.
  267.  
  268.   ENDMETHOD.
  269.  
  270.   METHOD planificar_job.
  271.  
  272.     DATA lv_jobcount TYPE btcjobcnt.
  273.     DATA(lv_jobname) = CONV btcjob( c_report ).
  274.  
  275.     "1) Abrir el job
  276.     CALL FUNCTION 'JOB_OPEN'
  277.       EXPORTING  jobname          = lv_jobname
  278.       IMPORTING  jobcount         = lv_jobcount
  279.       EXCEPTIONS cant_create_job  = 1
  280.                  invalid_job_data = 2
  281.                  jobname_missing  = 3
  282.                  OTHERS           = 4.
  283.  
  284.     IF sy-subrc <> 0.
  285.       MESSAGE 'Error al abrir el nuevo job de monitorizacion' TYPE 'S'.
  286.       RETURN.
  287.     ENDIF.
  288.  
  289.     "2) Incluir este mismo programa con los parametros de entrada
  290.     SUBMIT (c_report)
  291.       VIA JOB lv_jobname NUMBER lv_jobcount
  292.       WITH p_job   = i_job
  293.       WITH p_jobn  = i_jobn
  294.       WITH s_fecha IN s_fecha[]
  295.       WITH p_email = g_email
  296.       WITH p_delay = g_delay
  297.       AND RETURN.
  298.  
  299.     "3) Cerrar el job con la fecha/hora de inicio deseada
  300.     CALL FUNCTION 'JOB_CLOSE'
  301.       EXPORTING  jobcount             = lv_jobcount
  302.                  jobname              = lv_jobname
  303.                  sdlstrtdt            = i_fecha
  304.                  sdlstrttm            = i_hora
  305.       EXCEPTIONS cant_start_immediate = 1
  306.                  invalid_startdate    = 2
  307.                  jobname_missing      = 3
  308.                  job_close_failed     = 4
  309.                  job_nosteps          = 5
  310.                  job_notex            = 6
  311.                  lock_failed          = 7
  312.                  OTHERS               = 8.
  313.  
  314.     IF sy-subrc <> 0.
  315.       MESSAGE 'Error al planificar el nuevo job de monitorizacion' TYPE 'S'.
  316.     ENDIF.
  317.  
  318.   ENDMETHOD.
  319.  
  320.   METHOD job_activo.
  321.  
  322.     SELECT SINGLE status FROM tbtco
  323.       INTO @DATA(lv_status)
  324.       WHERE jobname  = @i_job
  325.         AND jobcount = @i_jobn.
  326.  
  327.     r_activo = xsdbool( sy-subrc = 0 AND lv_status = c_status_activo ).
  328.  
  329.   ENDMETHOD.
  330.  
  331.   METHOD leer_datos_job.
  332.  
  333.     SELECT SINGLE * FROM tbtco
  334.       INTO @r_job
  335.       WHERE jobname  = @i_job
  336.         AND jobcount = @i_jobn.
  337.  
  338.   ENDMETHOD.
  339.  
  340.   METHOD enviar_email.
  341.  
  342.     "Determinar la maquina (servidor) donde se ha ejecutado el job
  343.     DATA(lv_maquina) = COND btcsrvname(
  344.       WHEN i_job-execserver IS NOT INITIAL THEN i_job-execserver
  345.       ELSE i_job-reaxserver ).
  346.  
  347.     "Construir el cuerpo del mensaje
  348.     DATA(lt_body) = VALUE soli_tab(
  349.       ( line = 'El job ha finalizado' )
  350.       ( line = |Estado   : { texto_estado( i_job-status ) }| )
  351.       ( line = |Maquina  : { lv_maquina }| )
  352.       ( line = |Mandante : { sy-mandt }| )
  353.       ( line = |Inicio   : { i_job-strtdate DATE = USER } { i_job-strttime TIME = USER }| )
  354.       ( line = |Fin      : { i_job-enddate DATE = USER } { i_job-endtime TIME = USER }| ) ).
  355.  
  356.     "Enviar el correo mediante la clase estandar del proyecto. Se solicita
  357.     "el envio inmediato (i_immediate = abap_true) para que SOLO este correo
  358.     "salga al instante y no quede en espera en la SOST; el resto de la cola
  359.     "de SAPconnect no se ve afectada.
  360.     DATA(lo_mail) = NEW zini_cl_email( ).
  361.     lo_mail->set_subject( CONV #( i_job-jobname ) ). " Asunto = nombre del job
  362.     lo_mail->set_body( lt_body ).
  363.     lo_mail->set_to( CONV #( g_email ) ).
  364.     lo_mail->set_from( CONV #( 'email@email.com' ) ).
  365.     lo_mail->send_email( i_immediate = abap_true ).
  366.  
  367.   ENDMETHOD.
  368.  
  369.   METHOD texto_estado.
  370.  
  371.     r_texto = SWITCH #( i_status
  372.       WHEN 'R' THEN 'En ejecucion (activo)'
  373.       WHEN 'F' THEN 'Finalizado correctamente'
  374.       WHEN 'A' THEN 'Cancelado'
  375.       WHEN 'S' THEN 'Liberado / Programado'
  376.       WHEN 'P' THEN 'Planificado'
  377.       WHEN 'Y' THEN 'Preparado para ejecucion'
  378.       WHEN 'Z' THEN 'En espera de evento'
  379.       ELSE |Desconocido ({ i_status })| ).
  380.  
  381.   ENDMETHOD.
  382.  
  383. ENDCLASS.
  384.  
  385. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  386. *--[ Logica principal
  387. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  388. START-OF-SELECTION.
  389.  
  390.   DATA(go_tool) = NEW lcl_monitor( i_job   = p_job
  391.                                    i_jobn  = p_jobn
  392.                                    i_email = p_email
  393.                                    i_delay = p_delay ).
  394.   go_tool->ejecutar( ).

SAP ABAP Programación Class

Última modificación de la página el 02 October 2026 a las 12h41
Powered by PmWiki