BTP - Application Job (Internal API)
How to schedule a job in the system when we are in the middle of processing our application? In this article you will learn more about the API.
Table of contents
Jobs are not only scheduled via the Fiori apps, but must also be able to be scheduled in applications without user intervention. In this article we will show you how you can use the API and how you can easily run jobs in the system.
Introduction
When it comes to scheduling and executing jobs in the system, the released API comes in the form of the CL_APJ_RT_API class. These classes provide methods with which you can schedule simple execution or recurring patterns. If you want to schedule an application job, then you should use this API.
Preperation
Before we start calling the API, we need a few parameters for our job. Some parameters in the template are mandatory and are checked through validations, which is why we prepare a set of parameters before scheduling for all examples. We keep the parameters in a table as an attribute (member) of the class.
DATA mt_parameter TYPE cl_apj_rt_api=>tt_job_parameter_value.
mt_parameter = VALUE cl_apj_rt_api=>tt_job_parameter_value(
( name = 'TEXT' t_value = VALUE #( ( sign = 'I' option = 'EQ' low = 'Planned Job' ) ) )
( name = 'COUNTRY' t_value = VALUE #( ( sign = 'I' option = 'BT' low = 'DE' high = 'EN' ) ) )
( name = 'R_TEXT' t_value = VALUE #( ( sign = 'I' option = 'EQ' low = abap_false ) ) )
( name = 'R_LAND' t_value = VALUE #( ( sign = 'I' option = 'EQ' low = abap_true ) ) )
( name = 'TEST' t_value = VALUE #( ( sign = 'I' option = 'EQ' low = abap_false ) ) ) ).
We have already created the job we use in this example in another article. You can find further information on creating and using application jobs via the link.
Scheduling
To schedule a job, we need the SCHEDULE_JOB method of the class, which provides the necessary interface to schedule the job in the system.
Single run
In the first step we want to run the job once, directly after calling the method. To do this, we fill the interface with the required information. This also includes the job template that we created, plus the corresponding parameters and start options.
DATA(ls_start) = VALUE cl_apj_rt_api=>ty_start_info( start_immediately = abap_true ).
cl_apj_rt_api=>schedule_job( EXPORTING iv_job_template_name = 'ZBS_DEMO_JOB_ADT_TEMPLATE'
iv_job_text = 'Single run from Code (Immediately)'
is_start_info = ls_start
it_job_parameter_value = mt_parameter
IMPORTING ev_jobname = DATA(ld_jobname)
ev_jobcount = DATA(ld_jobcount) ).
out->write( |Job planned under Jobname { ld_jobname } and Jobcount { ld_jobcount }| ).
After executing the coding, we receive the success message and the output of the job name and job count in the console. We'll get more information about the job about the two values later:
If we then check the Fiori app “Application Jobs”, we will find the job there with the corresponding name. Since the job has a very short runtime, it has already been carried out and is set to "Finished".
Recurring
Next we schedule a recurring job, which should start immediately and then be repeated twice. The source code for scheduling the job now looks like this:
DATA(ls_start) = VALUE cl_apj_rt_api=>ty_start_info( ).
GET TIME STAMP FIELD ls_start-timestamp.
ls_start-timestamp = cl_abap_tstmp=>add( tstmp = ls_start-timestamp
secs = 120 ).
DATA(ls_end) = VALUE cl_apj_rt_api=>ty_end_info( type = 'NUM' max_iterations = 3 ).
DATA(ls_scheduling_info) = VALUE cl_apj_rt_api=>ty_scheduling_info(
periodic_granularity = 'W'
periodic_value = 1
test_mode = abap_false
timezone = 'CET'
weekday_info = VALUE #( on_tuesday = abap_true on_saturday = abap_true ) ).
cl_apj_rt_api=>schedule_job( EXPORTING iv_job_template_name = 'ZBS_DEMO_JOB_ADT_TEMPLATE'
iv_job_text = 'Recurring run'
is_start_info = ls_start
it_job_parameter_value = mt_parameter
is_end_info = ls_end
is_scheduling_info = ls_scheduling_info
IMPORTING ev_jobname = DATA(ld_jobname)
ev_jobcount = DATA(ld_jobcount) ).
The following explanation is provided to help you better classify the parts:
- Start - This time we are setting the timestamp to schedule the job at a specific time rather than immediately. We add two minutes to the current time.
- End - We want the job to terminate after two repetitions, so we set the TYPE to 'NUM', i.e. number, and the number of repetitions to 3. The current run also counts, so for two repetitions we need the number of three Jobs.
- Scheduling - We set the scheduling with 'W' to weekly and the frequency to 1, i.e. every week. The job should only run on Tuesday and Saturday weekdays. However, it is important that the immediate start also runs on one of the two days, otherwise you will have an interruption in processing.
After scheduling, the jobs can be found again in the app. If you also make the restriction for the future, then you will also find the planned jobs.
Constants
To schedule the jobs, various values are required, which are mapped as a constant structure in the IF_APJ_RT_TYPES interface. Since the interface is not released at the moment, the values have to be hard deposited in the code, but can be viewed here. The values in the fixed values can also be found via the structures and the domains. You can also display them in the ABAP Development Tools via the Element Info:
Informations
In some places we want to check the current status of a job or perhaps read more information about a job, there are also different methods to get the information. If we simply need the status and the corresponding text, the GET_JOB_STATUS method is available:
cl_apj_rt_api=>get_job_status( EXPORTING iv_jobname = 'FEDC1903ACDA1EEEABE45F7233854BD6'
iv_jobcount = 'Bsgasykr'
IMPORTING ev_job_status = DATA(ld_status)
ev_job_status_text = DATA(ld_text) ).
out->write( |Status: { ld_status } - { ld_text }| ).
This gives us the following result as output in the Console:
If you need some more information about the job, perhaps also the runtime, the user or information about the template used, then you can use the GET_JOB_DETAILS method:
DATA(ls_job_details) = cl_apj_rt_api=>get_job_details( iv_jobname = 'FEDC1903ACDA1EEEABE45F7233854BD6'
iv_jobcount = 'Bsgasykr' ).
The result of the query here in the variable view in the ABAP Development Tools:
Other methods
Explaining all the methods of the API would go beyond the scope of the article. However, the class still offers various methods to carry out further actions, for example:
- CANCEL_JOB - Cancel a running job.
- FIND_JOBS_WITH_JCE - Search for jobs that use the corresponding template. Only jobs that are running or scheduled for the future are returned.
- COPY_JOB - Copy a job.
- GENERATE_JOBKEY - Generation of job name and job count, even before the job is scheduled. With this information, a job can be scheduled and automatic assignment can be prevented.
Full example
Here you can find the complete executable class for testing. The READ_JOB_INFO method must be filled with values from your system, here you can find our dummy values for the job run:
CLASS zcl_bs_demo_job_api DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
PRIVATE SECTION.
DATA mt_parameter TYPE cl_apj_rt_api=>tt_job_parameter_value.
METHODS plan_single_run
IMPORTING io_out TYPE REF TO if_oo_adt_classrun_out.
METHODS plan_recurring_runs
IMPORTING io_out TYPE REF TO if_oo_adt_classrun_out.
METHODS read_job_info
IMPORTING io_out TYPE REF TO if_oo_adt_classrun_out.
ENDCLASS.
CLASS zcl_bs_demo_job_api IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
mt_parameter = VALUE cl_apj_rt_api=>tt_job_parameter_value(
( name = 'TEXT' t_value = VALUE #( ( sign = 'I' option = 'EQ' low = 'Planned Job' ) ) )
( name = 'COUNTRY' t_value = VALUE #( ( sign = 'I' option = 'BT' low = 'DE' high = 'EN' ) ) )
( name = 'R_TEXT' t_value = VALUE #( ( sign = 'I' option = 'EQ' low = abap_false ) ) )
( name = 'R_LAND' t_value = VALUE #( ( sign = 'I' option = 'EQ' low = abap_true ) ) )
( name = 'TEST' t_value = VALUE #( ( sign = 'I' option = 'EQ' low = abap_false ) ) ) ).
plan_single_run( out ).
plan_recurring_runs( out ).
read_job_info( out ).
ENDMETHOD.
METHOD plan_single_run.
TRY.
DATA(ls_start) = VALUE cl_apj_rt_api=>ty_start_info( start_immediately = abap_true ).
cl_apj_rt_api=>schedule_job( EXPORTING iv_job_template_name = 'ZBS_DEMO_JOB_ADT_TEMPLATE'
iv_job_text = 'Single run from Code (Immediately)'
is_start_info = ls_start
it_job_parameter_value = mt_parameter
IMPORTING ev_jobname = DATA(ld_jobname)
ev_jobcount = DATA(ld_jobcount) ).
io_out->write( |Job planned under Jobname { ld_jobname } and Jobcount { ld_jobcount }| ).
CATCH cx_apj_rt INTO DATA(lo_error).
io_out->write( lo_error->get_text( ) ).
ENDTRY.
ENDMETHOD.
METHOD plan_recurring_runs.
TRY.
DATA(ls_start) = VALUE cl_apj_rt_api=>ty_start_info( ).
GET TIME STAMP FIELD ls_start-timestamp.
ls_start-timestamp = cl_abap_tstmp=>add( tstmp = ls_start-timestamp
secs = 120 ).
DATA(ls_end) = VALUE cl_apj_rt_api=>ty_end_info( type = 'NUM' max_iterations = 3 ).
DATA(ls_scheduling_info) = VALUE cl_apj_rt_api=>ty_scheduling_info(
periodic_granularity = 'W'
periodic_value = 1
test_mode = abap_false
timezone = 'CET'
weekday_info = VALUE #( on_tuesday = abap_true on_saturday = abap_true ) ).
cl_apj_rt_api=>schedule_job( EXPORTING iv_job_template_name = 'ZBS_DEMO_JOB_ADT_TEMPLATE'
iv_job_text = 'Recurring run'
is_start_info = ls_start
it_job_parameter_value = mt_parameter
is_end_info = ls_end
is_scheduling_info = ls_scheduling_info
IMPORTING ev_jobname = DATA(ld_jobname)
ev_jobcount = DATA(ld_jobcount) ).
io_out->write( |Job planned under Jobname { ld_jobname } and Jobcount { ld_jobcount }| ).
CATCH cx_apj_rt INTO DATA(lo_error).
io_out->write( lo_error->get_text( ) ).
ENDTRY.
ENDMETHOD.
METHOD read_job_info.
cl_apj_rt_api=>get_job_status( EXPORTING iv_jobname = 'FEDC1903ACDA1EEEABE45F7233854BD6'
iv_jobcount = 'Bsgasykr'
IMPORTING ev_job_status = DATA(ld_status)
ev_job_status_text = DATA(ld_text) ).
io_out->write( |Status: { ld_status } - { ld_text }| ).
DATA(ls_job_details) = cl_apj_rt_api=>get_job_details( iv_jobname = 'FEDC1903ACDA1EEEABE45F7233854BD6'
iv_jobcount = 'Bsgasykr' ).
io_out->write( ls_job_details ).
ENDMETHOD.
ENDCLASS.
ABAP Cloud
Function modules like JOB_OPEN no longer work in the world of ABAP Cloud because the objects are not available to the developer in TIER-1. In the case of application jobs, the object to be automated has also changed (report to class). You can use the Cloudification Repository Viewer to find the successor objects or API so that you can schedule jobs via your processing as usual.
Conclusion
Scheduling application jobs is done quite easily with a method call. The provided API allows us to perform all the basic operations to schedule, cancel and read information about a job.