Run PL/SQL in the background and display a progress bar
Publish Date |
APEX version |
Database version |
February 2017 |
all |
all |
To run PL/SQL procedures within an Application Express application, is daily developers work. All business logic
within APEX is done with PL/SQL. Sometimes, PL/SQL procedures might take more time to complete - and since we are talking
about web applications, that means that the end users will have to wait for their browsers to respond. This is OK up to a few
seconds, but when execution times reach minutes, this quickly becomes inacceptable.
In this how to document, you will learn, how to run PL/SQL code in the background using the database package
DBMS_SCHEDULER, how to query the jobs' status and how to display a nice progress bar
in your application which informs end users about the status of their background operation.
Send PL/SQL code to the background
Background PL/SQL code is, from the database's point of view, a scheduler job. Database
administrators use these frequently - for application developers, it's not that common. As an example, we will use the
following PL/SQL procedure (replace {my-workspace} with your workspace name).
If we ran that PL/SQL procedure as a "normal" page process of type PL/SQL, the browser would indeed be stalled for
5 minutes. That is not only a very long time to wait, in some environments, the front-end webservers even terminate connections
after some time. So, for the end user, the APEX page might even error out.
So we run that code as a job, using
DBMS_SCHEDULER. On your Application Express instance, you will need the
CREATE JOB privilege for that. On the public
Oracle evaluation instance apex.oracle.com, the
privilege is already granted.
Create an Application Express application and a page within that app. Then create a page process of type
PL/SQL using the above code. Create a button on your page (Run Job) and
have the page process being executed upon button click. When you run the page and click the button, the result
should look as follows.
The PL/SQL code has been fired as a background job
Using the data dictionary view USER_SCHEDULER_JOBS, you can verify whether your job is really running. The view
contains much more columns providing all kind of information about your job - have a look. There is also the
view USER_SCHEDULER_JOB_RUN_DETAILS in which you can check results or issues of already finished jobs. To provide
that information to the end user, you might simply use Application Express reports.
But that is not really satisfying - we can see that a job is running, but not how far it already got. In our case, we could
simply check the expired time (we know that the job runs 5 minutes), but in practice, things are not so easy. Jobs might
have to work on a number of table rows - and we cannot simply map that to expired minutes or seconds. We would like to have
our job frequently reporting on its status - and the following sections will explain how this can work.
Excursion: Desupport of the APEX_PLSQL_JOB package
As already announced with the APEX 5.0 release, APEX_PLSQL_JOB
(which relied on the old DBMS_JOB package) has been removed.
APEX_PLSQL_JOB was used to run PL/SQL logic in the background in the
very early APEX releases. Since we have DBMS_SCHEDULER since Oracle10g (that means, since 2004), that package
has been removed with APEX 5.1. Applications using APEX_PLSQL_JOB
should be migrated to use DBMS_SCHEDULER, preferrable before the instance is upgraded to 5.1.
Here is an example for some
code to run PL/SQL logic in background with APEX_PLSQL_JOB:
The following code does the same; but uses DBMS_SCHEDULER.
Applications or PL/SQL code using APEX_PLSQL_JOB
should therefore be migrated to use DBMS_SCHEDULER. That should be
done even when still on APEX 5.0 or 4.2. Having this done, applications will run without issues
after the upgrade to 5.1.
Report job status to Database Administrators and End Users
Background jobs executed with DBMS_SCHEDULER run within their own database session, so an APEX component cannot
look into global PL/SQL package variables. The job could maintain status within their own tables, but that would
require the job to also commit after each status update. Also, we want to use the most generic infrastructure as
possible: not only APEX end users are interested in the jobs' status, that information is important for
database administrators as well.
The Oracle database contains a built-in facility to report on the status of a long running job:
The V$SESSION_LONGOPS data dictionary view. And Oracle itself uses that view: When
executing a CREATE TABLE AS SELECT statement to copy a very large table, you can monitor the progress using this
view. Every database user can access V$SESSION_LONGOPS, so we can use it within
our APEX application. Also, the database administrator knows about that view, uses it frequently and so gets informed
about long running operations of the APEX application.
To report status information to
V$SESSION_LONGOPS, we have to use the
DBMS_APPLICATION_INFO.SET_SESSION_LONGOPS procedure. Its interface is
a bit cumbersome, to make it more easy, we first create ourselves a tiny
"Wrapper-Package" ...
Our new PKG_SESSION_LONGOPS package contains two procedures:
DO_INIT creates a new entry in
V$SESSION_LONGOPS for our job. DO_UPDATE
reports a status update to that entry. V$SESSION_LONGOPS is not transactional, it's not really a table. All operations
are done in memory and should therefore have no performance impact. So change the DO_LONGRUN procedure we have
created at the beginning, to use the new PKG_SESSION_LONGOPS package as follows:
Now run your page and fire another job execution. Using SQL Plus or SQL Workshop you can monitor job status.
Display job status as a progress bar
Using the above SQL query, we can easily create an APEX report ...
... and for the PERCENT column (which returns a value between 0 and 100),
the Percent Graph type is a perfect fit.
Change a report column type to "Percent Graph"
The result should look as in the following screenshot. You might even extend that to have the report
automatically refresh using the Timer plug-in from the Application Express Plug-Ins page.
Report job status to the end user with a progress bar
Summary
In this how to document you have learned how to use the DBMS_SCHEDULER
package to run PL/SQL procedures as a background job. That is particularly useful for PL/SQL operations which
require more than a few seconds to complete. End users don't experience a stalled browser and application
acceptance will increase.
Using the V$SESSION_LONGOPS view the job can frequently report on its current status;
with APEX reports or charts we are then able to provide such status information to the end user.
back to blogs.oracle.com/apex
|