Background Jobs enable time-controlled or event-based execution of ABAP programs without user interaction. With JOB_OPEN, SUBMIT, and JOB_CLOSE, jobs can be created and scheduled programmatically.
Basic Concept
| Function | Description |
|---|---|
JOB_OPEN | Create and open job |
SUBMIT ... VIA JOB | Add report to job |
JOB_CLOSE | Close and schedule job |
BP_JOB_DELETE | Delete job |
BP_JOB_READ | Read job status |
Job Status
| Status | Meaning |
|---|---|
| P (Planned) | Planned, waiting to start |
| S (Scheduled) | Released |
| R (Running) | Currently running |
| F (Finished) | Successfully completed |
| A (Aborted) | Aborted |
Examples
1. Create a Simple Job
DATA: lv_jobname TYPE btcjob VALUE 'ZTEST_JOB', lv_jobcount TYPE btcjobcnt.
" Open jobCALL FUNCTION 'JOB_OPEN' EXPORTING jobname = lv_jobname IMPORTING jobcount = lv_jobcount EXCEPTIONS cant_create_job = 1 invalid_job_data = 2 jobname_missing = 3 OTHERS = 4.
IF sy-subrc <> 0. MESSAGE 'Job could not be created' TYPE 'E'. RETURN.ENDIF.
" Add report to jobSUBMIT zreport VIA JOB lv_jobname NUMBER lv_jobcount AND RETURN.
" Close job and start immediatelyCALL FUNCTION 'JOB_CLOSE' EXPORTING jobcount = lv_jobcount jobname = lv_jobname strtimmed = abap_true " Start immediately EXCEPTIONS cant_start_immediate = 1 invalid_startdate = 2 jobname_missing = 3 job_close_failed = 4 job_nosteps = 5 job_notex = 6 lock_failed = 7 OTHERS = 8.
IF sy-subrc = 0. MESSAGE |Job { lv_jobname } was started| TYPE 'S'.ENDIF.2. Schedule Job with Start Time
DATA: lv_jobname TYPE btcjob VALUE 'ZNIGHTLY_REPORT', lv_jobcount TYPE btcjobcnt, lv_startdate TYPE sy-datum, lv_starttime TYPE sy-uzeit.
" Start tomorrow at 02:00lv_startdate = sy-datum + 1.lv_starttime = '020000'.
" Open jobCALL FUNCTION 'JOB_OPEN' EXPORTING jobname = lv_jobname IMPORTING jobcount = lv_jobcount EXCEPTIONS OTHERS = 1.
IF sy-subrc <> 0. RETURN.ENDIF.
" Add reportSUBMIT zreport_nightly VIA JOB lv_jobname NUMBER lv_jobcount AND RETURN.
" Schedule job with start timeCALL FUNCTION 'JOB_CLOSE' EXPORTING jobcount = lv_jobcount jobname = lv_jobname sdlstrtdt = lv_startdate " Start date sdlstrttm = lv_starttime " Start time EXCEPTIONS OTHERS = 1.
IF sy-subrc = 0. MESSAGE |Job scheduled for { lv_startdate DATE = USER } { lv_starttime TIME = USER }| TYPE 'S'.ENDIF.3. Job with Selection Parameters
DATA: lv_jobname TYPE btcjob VALUE 'ZCUSTOMER_EXPORT', lv_jobcount TYPE btcjobcnt, lt_seltab TYPE TABLE OF rsparams, lv_variant TYPE raldb_vari.
" Build selection parameterslt_seltab = VALUE #( ( selname = 'P_BUKRS' kind = 'P' sign = 'I' option = 'EQ' low = '1000' ) ( selname = 'P_DATE' kind = 'P' sign = 'I' option = 'EQ' low = sy-datum ) ( selname = 'S_KUNNR' kind = 'S' sign = 'I' option = 'BT' low = '0000001000' high = '0000009999' )).
CALL FUNCTION 'JOB_OPEN' EXPORTING jobname = lv_jobname IMPORTING jobcount = lv_jobcount EXCEPTIONS OTHERS = 1.
" Report with selection parametersSUBMIT zcustomer_report VIA JOB lv_jobname NUMBER lv_jobcount WITH SELECTION-TABLE lt_seltab AND RETURN.
CALL FUNCTION 'JOB_CLOSE' EXPORTING jobcount = lv_jobcount jobname = lv_jobname strtimmed = abap_true EXCEPTIONS OTHERS = 1.4. Job with Variant
" Execute report with saved variantSUBMIT zmonthly_report VIA JOB lv_jobname NUMBER lv_jobcount USING SELECTION-SET 'MONTHLY_DEFAULT' " Variant AND RETURN.5. Periodic Job (Daily, Weekly)
DATA: lv_jobname TYPE btcjob VALUE 'ZDAILY_CLEANUP', lv_jobcount TYPE btcjobcnt, ls_period TYPE tbtcjob-periodic, lv_prdmonths TYPE tbtcjob-prdmonths, lv_prdweeks TYPE tbtcjob-prdweeks, lv_prddays TYPE tbtcjob-prddays, lv_prdhours TYPE tbtcjob-prdhours, lv_prdmins TYPE tbtcjob-prdmins.
" Open jobCALL FUNCTION 'JOB_OPEN' EXPORTING jobname = lv_jobname IMPORTING jobcount = lv_jobcount EXCEPTIONS OTHERS = 1.
SUBMIT zcleanup_report VIA JOB lv_jobname NUMBER lv_jobcount AND RETURN.
" Daily at 23:00CALL FUNCTION 'JOB_CLOSE' EXPORTING jobcount = lv_jobcount jobname = lv_jobname sdlstrtdt = sy-datum sdlstrttm = '230000' prddays = 1 " Every 1 day periodic = abap_true " Periodic EXCEPTIONS OTHERS = 1.
" Alternative: Weekly (every Monday)CALL FUNCTION 'JOB_CLOSE' EXPORTING jobcount = lv_jobcount jobname = lv_jobname sdlstrtdt = '20240101' " First Monday sdlstrttm = '060000' prdweeks = 1 " Weekly periodic = abap_true EXCEPTIONS OTHERS = 1.6. Job Class for Reusable Jobs
CLASS zcl_job_scheduler DEFINITION. PUBLIC SECTION. TYPES: BEGIN OF ty_job_info, jobname TYPE btcjob, jobcount TYPE btcjobcnt, status TYPE btcstatus, END OF ty_job_info.
METHODS: schedule_report IMPORTING iv_report TYPE progname iv_variant TYPE raldb_vari OPTIONAL it_params TYPE rsparams_tt OPTIONAL iv_start_date TYPE sy-datum DEFAULT sy-datum iv_start_time TYPE sy-uzeit DEFAULT sy-uzeit iv_immediate TYPE abap_bool DEFAULT abap_false RETURNING VALUE(rs_job) TYPE ty_job_info RAISING zcx_job_error.
METHODS: get_job_status IMPORTING iv_jobname TYPE btcjob iv_jobcount TYPE btcjobcnt RETURNING VALUE(rv_status) TYPE btcstatus.
METHODS: wait_for_job IMPORTING iv_jobname TYPE btcjob iv_jobcount TYPE btcjobcnt iv_timeout TYPE i DEFAULT 300 RETURNING VALUE(rv_success) TYPE abap_bool.
PRIVATE SECTION. METHODS: generate_jobname IMPORTING iv_prefix TYPE string RETURNING VALUE(rv_name) TYPE btcjob.ENDCLASS.
CLASS zcl_job_scheduler IMPLEMENTATION. METHOD schedule_report. " Generate jobname rs_job-jobname = generate_jobname( iv_report ).
" Open job CALL FUNCTION 'JOB_OPEN' EXPORTING jobname = rs_job-jobname IMPORTING jobcount = rs_job-jobcount EXCEPTIONS cant_create_job = 1 OTHERS = 2.
IF sy-subrc <> 0. RAISE EXCEPTION TYPE zcx_job_error EXPORTING textid = zcx_job_error=>job_open_failed. ENDIF.
" Schedule report IF iv_variant IS NOT INITIAL. SUBMIT (iv_report) VIA JOB rs_job-jobname NUMBER rs_job-jobcount USING SELECTION-SET iv_variant AND RETURN. ELSEIF it_params IS NOT INITIAL. SUBMIT (iv_report) VIA JOB rs_job-jobname NUMBER rs_job-jobcount WITH SELECTION-TABLE it_params AND RETURN. ELSE. SUBMIT (iv_report) VIA JOB rs_job-jobname NUMBER rs_job-jobcount AND RETURN. ENDIF.
" Close job IF iv_immediate = abap_true. CALL FUNCTION 'JOB_CLOSE' EXPORTING jobcount = rs_job-jobcount jobname = rs_job-jobname strtimmed = abap_true EXCEPTIONS OTHERS = 1. ELSE. CALL FUNCTION 'JOB_CLOSE' EXPORTING jobcount = rs_job-jobcount jobname = rs_job-jobname sdlstrtdt = iv_start_date sdlstrttm = iv_start_time EXCEPTIONS OTHERS = 1. ENDIF.
IF sy-subrc <> 0. RAISE EXCEPTION TYPE zcx_job_error EXPORTING textid = zcx_job_error=>job_close_failed. ENDIF.
rs_job-status = 'S'. " Scheduled ENDMETHOD.
METHOD generate_jobname. DATA(lv_timestamp) = |{ sy-datum }{ sy-uzeit }|. rv_name = |{ iv_prefix(20) }_{ lv_timestamp }|. ENDMETHOD.
METHOD get_job_status. DATA: ls_job TYPE tbtcjob.
CALL FUNCTION 'BP_JOB_READ' EXPORTING job_read_jobcount = iv_jobcount job_read_jobname = iv_jobname job_read_opcode = '20' IMPORTING job_read_jobhead = ls_job EXCEPTIONS OTHERS = 1.
IF sy-subrc = 0. rv_status = ls_job-status. ENDIF. ENDMETHOD.
METHOD wait_for_job. DATA: lv_start TYPE i, lv_elapsed TYPE i, lv_status TYPE btcstatus.
GET RUN TIME FIELD lv_start.
DO. lv_status = get_job_status( iv_jobname = iv_jobname iv_jobcount = iv_jobcount ).
CASE lv_status. WHEN 'F'. " Finished rv_success = abap_true. RETURN. WHEN 'A'. " Aborted rv_success = abap_false. RETURN. ENDCASE.
" Check timeout GET RUN TIME FIELD lv_elapsed. IF ( lv_elapsed - lv_start ) / 1000000 > iv_timeout. rv_success = abap_false. RETURN. ENDIF.
" Wait WAIT UP TO 5 SECONDS. ENDDO. ENDMETHOD.ENDCLASS.
" UsageDATA(lo_scheduler) = NEW zcl_job_scheduler( ).
TRY. DATA(ls_job) = lo_scheduler->schedule_report( iv_report = 'ZMONTHLY_REPORT' iv_variant = 'DEFAULT' iv_immediate = abap_true ).
" Wait for completion IF lo_scheduler->wait_for_job( iv_jobname = ls_job-jobname iv_jobcount = ls_job-jobcount iv_timeout = 600 ) = abap_true. MESSAGE 'Job completed successfully' TYPE 'S'. ELSE. MESSAGE 'Job failed or timeout' TYPE 'E'. ENDIF.
CATCH zcx_job_error INTO DATA(lx_error). MESSAGE lx_error->get_text( ) TYPE 'E'.ENDTRY.7. Job Chain (Multiple Steps)
DATA: lv_jobname TYPE btcjob VALUE 'ZCHAIN_JOB', lv_jobcount TYPE btcjobcnt.
CALL FUNCTION 'JOB_OPEN' EXPORTING jobname = lv_jobname IMPORTING jobcount = lv_jobcount EXCEPTIONS OTHERS = 1.
" Step 1: Load dataSUBMIT zload_data VIA JOB lv_jobname NUMBER lv_jobcount AND RETURN.
" Step 2: Process dataSUBMIT zprocess_data VIA JOB lv_jobname NUMBER lv_jobcount AND RETURN.
" Step 3: Create reportSUBMIT zcreate_report VIA JOB lv_jobname NUMBER lv_jobcount AND RETURN.
" Step 4: Send emailSUBMIT zsend_notification VIA JOB lv_jobname NUMBER lv_jobcount AND RETURN.
CALL FUNCTION 'JOB_CLOSE' EXPORTING jobcount = lv_jobcount jobname = lv_jobname strtimmed = abap_true EXCEPTIONS OTHERS = 1.8. Start Job on Event
DATA: lv_jobname TYPE btcjob VALUE 'ZEVENT_JOB', lv_jobcount TYPE btcjobcnt, lv_eventid TYPE btceventid VALUE 'SAP_END_OF_DAY', lv_eventparm TYPE btcevtparm.
CALL FUNCTION 'JOB_OPEN' EXPORTING jobname = lv_jobname IMPORTING jobcount = lv_jobcount EXCEPTIONS OTHERS = 1.
SUBMIT zend_of_day_processing VIA JOB lv_jobname NUMBER lv_jobcount AND RETURN.
" Start job on eventCALL FUNCTION 'JOB_CLOSE' EXPORTING jobcount = lv_jobcount jobname = lv_jobname event_id = lv_eventid event_param = lv_eventparm event_periodic = abap_true EXCEPTIONS OTHERS = 1.
" Raise event (e.g., from another program)CALL FUNCTION 'BP_EVENT_RAISE' EXPORTING eventid = 'SAP_END_OF_DAY' EXCEPTIONS bad_eventid = 1 eventid_does_not_exist = 2 eventid_missing = 3 raise_failed = 4 OTHERS = 5.9. Monitor Job Status
CLASS zcl_job_monitor DEFINITION. PUBLIC SECTION. TYPES: BEGIN OF ty_job_status, jobname TYPE btcjob, jobcount TYPE btcjobcnt, status TYPE btcstatus, startdate TYPE sy-datum, starttime TYPE sy-uzeit, enddate TYPE sy-datum, endtime TYPE sy-uzeit, duration TYPE i, END OF ty_job_status, ty_job_statuses TYPE STANDARD TABLE OF ty_job_status WITH KEY jobname jobcount.
METHODS: get_jobs_by_name IMPORTING iv_jobname_pattern TYPE btcjob RETURNING VALUE(rt_jobs) TYPE ty_job_statuses.
METHODS: get_failed_jobs IMPORTING iv_from_date TYPE sy-datum DEFAULT sy-datum RETURNING VALUE(rt_jobs) TYPE ty_job_statuses.ENDCLASS.
CLASS zcl_job_monitor IMPLEMENTATION. METHOD get_jobs_by_name. DATA: lt_joblist TYPE TABLE OF tbtcjob.
CALL FUNCTION 'BP_FIND_JOBS_WITH_PROGRAM' EXPORTING jobname = iv_jobname_pattern TABLES joblist = lt_joblist EXCEPTIONS OTHERS = 1.
LOOP AT lt_joblist INTO DATA(ls_job). APPEND VALUE #( jobname = ls_job-jobname jobcount = ls_job-jobcount status = ls_job-status startdate = ls_job-strtdate starttime = ls_job-strttime enddate = ls_job-enddate endtime = ls_job-endtime ) TO rt_jobs. ENDLOOP. ENDMETHOD.
METHOD get_failed_jobs. DATA: lt_joblist TYPE TABLE OF tbtcjob, ls_jobselect TYPE tbtcselect.
ls_jobselect-jobname = '*'. ls_jobselect-username = '*'. ls_jobselect-from_date = iv_from_date. ls_jobselect-to_date = sy-datum. ls_jobselect-aborted = abap_true.
CALL FUNCTION 'BP_JOB_SELECT' EXPORTING jobselect_dialog = abap_false jobsel_param_in = ls_jobselect TABLES jobselect_joblist = lt_joblist EXCEPTIONS OTHERS = 1.
LOOP AT lt_joblist INTO DATA(ls_job). APPEND VALUE #( jobname = ls_job-jobname jobcount = ls_job-jobcount status = ls_job-status startdate = ls_job-strtdate starttime = ls_job-strttime ) TO rt_jobs. ENDLOOP. ENDMETHOD.ENDCLASS.10. Delete Job
" Delete single jobCALL FUNCTION 'BP_JOB_DELETE' EXPORTING jobcount = lv_jobcount jobname = lv_jobname EXCEPTIONS cant_delete_job = 1 cant_delete_joblog = 2 doesnt_exist = 3 job_running = 4 OTHERS = 5.
IF sy-subrc = 0. MESSAGE 'Job deleted' TYPE 'S'.ELSEIF sy-subrc = 4. MESSAGE 'Job is still running - cannot be deleted' TYPE 'W'.ENDIF.
" Clean up old jobs (older than 30 days)DATA: lt_joblist TYPE TABLE OF tbtcjob, lv_cutoff TYPE sy-datum.
lv_cutoff = sy-datum - 30.
CALL FUNCTION 'BP_JOB_SELECT' EXPORTING jobselect_dialog = abap_false jobsel_param_in = VALUE tbtcselect( jobname = 'ZTEST*' username = '*' to_date = lv_cutoff finished = abap_true ) TABLES jobselect_joblist = lt_joblist EXCEPTIONS OTHERS = 1.
LOOP AT lt_joblist INTO DATA(ls_job). CALL FUNCTION 'BP_JOB_DELETE' EXPORTING jobcount = ls_job-jobcount jobname = ls_job-jobname EXCEPTIONS OTHERS = 1.ENDLOOP.11. Read Job Log
DATA: lt_joblog TYPE TABLE OF tbtc5.
CALL FUNCTION 'BP_JOBLOG_READ' EXPORTING jobcount = lv_jobcount jobname = lv_jobname TABLES joblogtbl = lt_joblog EXCEPTIONS cant_read_joblog = 1 jobcount_missing = 2 jobname_missing = 3 job_doesnt_exist = 4 OTHERS = 5.
IF sy-subrc = 0. LOOP AT lt_joblog INTO DATA(ls_log). WRITE: / ls_log-enterdate, ls_log-entertime, ls_log-text. ENDLOOP.ENDIF.12. Spool Output in Job
DATA: lv_jobname TYPE btcjob VALUE 'ZSPOOL_JOB', lv_jobcount TYPE btcjobcnt, ls_print TYPE pri_params.
" Set print parametersls_print-pdest = 'LOCL'. " Printerls_print-prnew = abap_true. " New spoolls_print-prtxt = 'Job Output'.ls_print-primm = abap_false. " Don't print immediatelyls_print-plist = 'X'. " Keep spool
CALL FUNCTION 'JOB_OPEN' EXPORTING jobname = lv_jobname IMPORTING jobcount = lv_jobcount EXCEPTIONS OTHERS = 1.
SUBMIT zreport_with_output VIA JOB lv_jobname NUMBER lv_jobcount TO SAP-SPOOL SPOOL PARAMETERS ls_print WITHOUT SPOOL DYNPRO AND RETURN.
CALL FUNCTION 'JOB_CLOSE' EXPORTING jobcount = lv_jobcount jobname = lv_jobname strtimmed = abap_true EXCEPTIONS OTHERS = 1.13. Job on Specific Server
" Start job on specific application serverCALL FUNCTION 'JOB_CLOSE' EXPORTING jobcount = lv_jobcount jobname = lv_jobname strtimmed = abap_true targetsystem = 'server_name_001' " Target server EXCEPTIONS OTHERS = 1.
" Or: Use server groupCALL FUNCTION 'JOB_CLOSE' EXPORTING jobcount = lv_jobcount jobname = lv_jobname strtimmed = abap_true jobclass = 'A' " Job class A (highest priority) EXCEPTIONS OTHERS = 1.14. XBP Interface for External Control
" For external job schedulers (Control-M, etc.)" Create parent jobDATA: lv_extprog TYPE btcxpg VALUE 'EXTERNAL_SCRIPT.SH'.
CALL FUNCTION 'JOB_OPEN' EXPORTING jobname = 'ZEXTERNAL_JOB' IMPORTING jobcount = lv_jobcount EXCEPTIONS OTHERS = 1.
" External program as stepCALL FUNCTION 'JOB_SUBMIT' EXPORTING jobcount = lv_jobcount jobname = 'ZEXTERNAL_JOB' extpgm_name = lv_extprog extpgm_param = '-p parameter1' extpgm_system = 'UNIX' EXCEPTIONS OTHERS = 1.
CALL FUNCTION 'JOB_CLOSE' EXPORTING jobcount = lv_jobcount jobname = 'ZEXTERNAL_JOB' strtimmed = abap_true EXCEPTIONS OTHERS = 1.15. Practical Example: Month-End Jobs
CLASS zcl_month_end_jobs DEFINITION. PUBLIC SECTION. METHODS: schedule_month_end IMPORTING iv_period TYPE monat iv_year TYPE gjahr RETURNING VALUE(rt_jobs) TYPE zcl_job_scheduler=>ty_job_info_tab.ENDCLASS.
CLASS zcl_month_end_jobs IMPLEMENTATION. METHOD schedule_month_end. DATA: lv_jobname TYPE btcjob, lv_jobcount TYPE btcjobcnt, lt_params TYPE rsparams_tt.
" Common parameters lt_params = VALUE #( ( selname = 'P_GJAHR' kind = 'P' low = iv_year ) ( selname = 'P_MONAT' kind = 'P' low = iv_period ) ).
" Job 1: Reconciliation lv_jobname = |ZMONTH_END_RECON_{ iv_year }{ iv_period }|.
CALL FUNCTION 'JOB_OPEN' EXPORTING jobname = lv_jobname IMPORTING jobcount = lv_jobcount EXCEPTIONS OTHERS = 1.
SUBMIT zreconciliation VIA JOB lv_jobname NUMBER lv_jobcount WITH SELECTION-TABLE lt_params AND RETURN.
CALL FUNCTION 'JOB_CLOSE' EXPORTING jobcount = lv_jobcount jobname = lv_jobname strtimmed = abap_true EXCEPTIONS OTHERS = 1.
APPEND VALUE #( jobname = lv_jobname jobcount = lv_jobcount ) TO rt_jobs.
" Job 2: Closing (starts after Job 1 via Event) lv_jobname = |ZMONTH_END_CLOSE_{ iv_year }{ iv_period }|.
CALL FUNCTION 'JOB_OPEN' EXPORTING jobname = lv_jobname IMPORTING jobcount = lv_jobcount EXCEPTIONS OTHERS = 1.
SUBMIT zperiod_close VIA JOB lv_jobname NUMBER lv_jobcount WITH SELECTION-TABLE lt_params AND RETURN.
CALL FUNCTION 'JOB_CLOSE' EXPORTING jobcount = lv_jobcount jobname = lv_jobname event_id = 'ZRECON_COMPLETE' event_param = |{ iv_year }{ iv_period }| EXCEPTIONS OTHERS = 1.
APPEND VALUE #( jobname = lv_jobname jobcount = lv_jobcount ) TO rt_jobs.
" Job 3: Reporting (starts after Job 2) lv_jobname = |ZMONTH_END_REPORT_{ iv_year }{ iv_period }|.
CALL FUNCTION 'JOB_OPEN' EXPORTING jobname = lv_jobname IMPORTING jobcount = lv_jobcount EXCEPTIONS OTHERS = 1.
SUBMIT zmonth_report VIA JOB lv_jobname NUMBER lv_jobcount WITH SELECTION-TABLE lt_params AND RETURN.
CALL FUNCTION 'JOB_CLOSE' EXPORTING jobcount = lv_jobcount jobname = lv_jobname event_id = 'ZCLOSE_COMPLETE' event_param = |{ iv_year }{ iv_period }| EXCEPTIONS OTHERS = 1.
APPEND VALUE #( jobname = lv_jobname jobcount = lv_jobcount ) TO rt_jobs. ENDMETHOD.ENDCLASS.Job Classes (Priorities)
| Class | Description |
|---|---|
| A | Highest priority |
| B | High priority |
| C | Normal priority (default) |
Important Notes / Best Practice
- Unique job names with date/time for traceability.
- Variants for repeated jobs with the same parameters.
- Events for job chains instead of fixed times.
- Choose job class according to urgency.
- Error handling in reports for meaningful logs.
- Configure spool output for logging.
- SM37 for manual job monitoring.
- Regularly clean up old jobs (performance).
- Check authorizations for job scheduling (S_BTCH_ADM, S_BTCH_JOB).
- Combine with Parallel Processing for performance.