Application Development Blog Posts
Learn and share on deeper, cross technology development topics such as integration and connectivity, automation, cloud extensibility, developing at scale, and security.
cancel
Showing results for 
Search instead for 
Did you mean: 
al_01
Explorer

Introduction


Hello fellow ABAPers,

have you ever encountered the situation where it might be helpful to monitor running batch jobs via ABAP-Reports (e.g. to get noticed automatically via email when a job fails)?

I want to share some basic ideas/snippets on this topic with the following blog post.

Snippets


It is quite "simple" to retrieve the status of a batch-job via function-module. FM
CALL FUNCTION 'BP_JOB_STATUS_GET'
EXPORTING
jobcount = p_jbcnt " Kennummer eines Jobs
jobname = p_jbnam " Name eines Hintergrundjobs
IMPORTING
status = job_status " Zustand eines Batchjobs
...

takes the corresponding job name + job count (ID) as input-parameter and returns the status of the job.

The problem is that the job-ID is unknown in advance. So it is not possible to predefine a report variant which passes the job name/job count to this function module.

But with the help of a Template-Job, which is making use of selection-variables (tvarvc), this lack of information can be overcome in a simple way (at least in my opinion :)).

Template of Job-Monitor


This example of a template for the job monitor is quite simple.

It consists of a single step (Z-Report) which only reads two selection-screen parameters and checks the status of the corresponding batch job in a while loop (until the job is finished or fails).


Selection-Screen of Job-Monitor



  WHILE job_status <> zcl_job_base=>btc_finished AND job_status <> zcl_job_base=>btc_aborted.
CALL FUNCTION 'BP_JOB_STATUS_GET'
EXPORTING
jobcount = p_jbcnt " Kennummer eines Jobs
jobname = p_jbnam " Name eines Hintergrundjobs
IMPORTING
status = job_status " Zustand eines Batchjobs
EXCEPTIONS
job_doesnt_exist = 1
unknown_error = 2
parent_child_inconsistency = 3
OTHERS = 4.
IF sy-subrc <> 0.
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
ENDIF.
IF job_status = zcl_job_base=>btc_finished.
"or write an email...
WRITE:/ |job: { p_jbnam } with Job-ID { p_jbcnt } finished| COLOR COL_POSITIVE.
ELSEIF job_status = zcl_job_base=>btc_aborted.
"or write an email...
WRITE:/ |job: { p_jbnam } with Job-ID { p_jbcnt } aborted| COLOR COL_NEGATIVE.
ELSE.
WAIT UP TO p_wait SECONDS.
ENDIF.
ENDWHILE.

The corresponding report variant would look like this (It is important to reference Selection-Variables)


Variant with Selection-Variables


Finally the step list:



Job with "Automatic" Monitoring


A second Z-Report is needed to make use of this Monitor-Template. The task of this report is to retrieve the current batch runtime info (job name/job count) and transfer this information to the previously defined selection-variables. The template job is then copied and released immediately. The result is an independent running monitoring job (of course, the monitoring job could fail as well (seems to be unlikely), but it is not affected by the result of the job which is being monitored). This report needs to run as the first step in order to implement "real-time" monitoring (before any other step is executed). The selection screen of this report looks like this:


First two parameters must match the name of the selection variables defined in the variant of the monitoring report. The third and fourth parameter are used to find and copy our template.
SELECTION-SCREEN BEGIN OF BLOCK bl_sel_par WITH FRAME TITLE TEXT-001.
PARAMETERS: p_jcnt TYPE tvarvc-name DEFAULT 'ZMONITOR_JOBCOUNT' OBLIGATORY,
p_jnam TYPE tvarvc-name DEFAULT 'ZMONITOR_JOBNAME' OBLIGATORY.
SELECTION-SCREEN END OF BLOCK bl_sel_par.

SELECTION-SCREEN BEGIN OF BLOCK bl_sel_job WITH FRAME TITLE TEXT-002.
PARAMETERS: p_jmsrc TYPE btcjob DEFAULT 'ZJOB_MONITOR' OBLIGATORY MATCHCODE OBJECT z_sh_planned_jobs.
PARAMETERS: p_jmtgt TYPE btcjob DEFAULT 'ZJOB_MONITOR_RUN'.
SELECTION-SCREEN END OF BLOCK bl_sel_job.

AT SELECTION-SCREEN ON p_jmsrc.
**********************************************************************
*** Check Copy Sources for Monitoring Job
SELECT FROM tbtco AS job_def
FIELDS COUNT( * ) AS cnt_cpy_srces
WHERE job_def~jobname EQ @p_jmsrc
AND job_def~status EQ @zcl_job_base=>btc_scheduled
INTO @DATA(l_cnt).
CASE l_cnt.
WHEN 0.
MESSAGE |Monitor-Job Copy Source not found!| TYPE 'E'.
WHEN 1.
WHEN OTHERS.
MESSAGE |There are more than 1 Copy Sources| TYPE 'W'.
ENDCASE.

START-OF-SELECTION.
*** Jobname and Jobcount (->Runtime-Info)
DATA: jobname TYPE tbtcm-jobname,
jobcount TYPE tbtcm-jobcount.
DATA: selpar_job_cnt TYPE REF TO zcl_sel_par,
selpar_job_name TYPE REF TO zcl_sel_par.
DATA: monitor_job TYPE REF TO zcl_job_mon.
DATA: enqueue_errors TYPE i.
CONSTANTS: max_enqueue_errors TYPE i VALUE 5.
**********************************************************************
IF sy-batch IS NOT INITIAL.
CALL FUNCTION 'GET_JOB_RUNTIME_INFO'
IMPORTING
jobcount = jobcount
jobname = jobname
EXCEPTIONS
no_runtime_info = 1
OTHERS = 2.
IF sy-subrc <> 0.
MESSAGE |Could not obtain Runtime-Info| TYPE 'E'.
ENDIF.
**********************************************************************
*** Jobcount and Jobname are transferred via Selection-Variables
TRY.
selpar_job_cnt = zcl_sel_var_factory=>create_selpar_with_e_lock( p_jcnt ).
selpar_job_cnt->set_value( jobcount ).
selpar_job_cnt->save_db( ).
selpar_job_name = zcl_sel_var_factory=>create_selpar_with_e_lock( p_jnam ).
selpar_job_name->set_value( jobname ).
selpar_job_name->save_db( ).
COMMIT WORK.
CATCH zcx_enqueue_error INTO DATA(lo_err). " Kein Treffer bei DB-Abfrage
enqueue_errors = enqueue_errors + 1.
IF enqueue_errors <= max_enqueue_errors.
WAIT UP TO 20 SECONDS.
RETRY.
ELSE.
MESSAGE |Could not perform enqueue: { lo_err->get_text( ) }| TYPE 'E'.
ENDIF.
ENDTRY.
*** Copy Monitor-Job and release immediatly

TRY.
CREATE OBJECT monitor_job
EXPORTING
iv_job_src_name = p_jmsrc.
"Copy Job to Default-Name
IF p_jmtgt IS INITIAL.
monitor_job->copy_to_target_job_dflt_name( ).
ELSE.
monitor_job->copy_to_target_job( iv_target_name = p_jmtgt iv_dialog = zcl_job_base=>z_btc_no ).
ENDIF.
monitor_job->release_target_job_now( ).
WRITE:/ |Job-Monitor for Job-Name: { p_jmtgt } released|.
*** dequeue after monitor job is released
TRY.
TYPES: range_status TYPE RANGE OF c.
WHILE monitor_job->get_state_of_target_job( )
IN VALUE range_status(
( option = 'EQ' sign = 'I' low = zcl_job_base=>btc_ready )
( option = 'EQ' sign = 'I' low = zcl_job_base=>btc_released ) ).
WAIT UP TO 15 SECONDS.
ENDWHILE.
CATCH zcx_job_error. " zcx_job_error
ENDTRY.
selpar_job_cnt->dequeue_tvarv( ).
selpar_job_name->dequeue_tvarv( ).
CATCH zcx_job_error.
MESSAGE |Could not release target Job for Job-Monitor| TYPE 'E'.
CATCH zcx_no_entry_found. " zcx_no_entry_found
MESSAGE |Copy-Source for Job-Monitor not found| TYPE 'E'.
ENDTRY.
ENDIF.

The selection-variables are enqueued and released after the monitor job is active and running in order to prevent unwanted overwriting (which makes this report somehow "thread safe").

Sample Job


Let's put this all together. Consider the following step list of a job called ZJOB_WITH_MONITORING:


Step list sample Job


The second step will make this job fail but let's take a look after the first step is executed.


Release of Job with Monitoring



First step...



Template Job is copied


You can see that report ZSUBMIT_JOB_MONITOR has read the current runtime info and has transferred this data to the selection variables:


Selection variant for zjob_monitor



Runtime Info of ZJOB_WITH_MONITORING


The job monitor now runs as an independent job which will not be affected by the failing of ZJOB_WITH_MONITORING as you can see in the next screenshot (the monitoring job could fail as well, but I don't see any obvious reasons for this).


Failing job but finishing job monitor



Result of monitoring



Conclusion


This simple example should demonstrate how "built-in" monitoring of batch jobs could be implemented with the help of a template job and usage of selection-variables (tvarvc).

There is only the need to include a step of report ZSUBMIT_JOB_MONITOR (first step) without having to define various variants for each job that should be monitored (of course, if more differentiation is needed depending on the job (or reaction on failing), there would be more variants, but if only some standard behavior is wanted - like sending an email "job xy failed at <<current_time>>" or raising events - this simple variant should be enough). Since enqueues are used to update the corresponding selection-variables (and only released after the monitoring job is running), this setup (same variables/variant) could be used by different jobs running/starting at the same time.

Coding snippets are available at github: (Please be aware that all BP-FMs are unreleased! The code is for demonstration only 🙂 )

Link to github

I hope you enjoyed reading this blog post (Sorry that some screenshots are partly in German, I wasn't aware when I took them and was too lazy to do it again 🙂 ).

How do you implement job monitoring? I am quite interested in your answers!

Cheers,

Alex!
14 Comments