Originally published: MC Press Online, on 10/30/2015.
Deliver real-time WRKACTJOB stats to the browser using Node.js, DB2 for i Services, and WebSockets.
I am continually intrigued by the capabilities HTML5’s WebSockets afford us on IBM i. In the article Node.js Is Genius with Web Sockets, I walked through the creation of a simple chat application that used WebSockets to communicate messages from the server to each browser currently participating in the chat. That was fun but not as immediately relevant to IBM i as it could have been. In this article, we will implement WebSockets into the IBM i Dash open-source project by adding an auto-updating page that conveys information equivalent to the WRKACTJOB command.
As a side note, the most recent V7.2 TR3 IBM i announcement includes Apache WebSocket support.
The ease of accessing WRKACTJOB-type information on IBM i has been made incredibly simple because of IBM’s growing ecosystem of DB2 for i Services. These services essentially make system information (formerly only accessible via complex API calls) very easy to obtain via a simple SQL statement. Below is an SQL
SELECT statement that calls upon the ACTIVE_JOB_INFO() User-Defined Table Function (UDTF). If you’re new to UDTFs, you should read this article by DB2 expert Birgitta Hauser that does an excellent job of introducing the subject matter.
SELECT JOB_NAME, AUTHORIZATION_NAME, ELAPSED_TOTAL_DISK_IO_COUNT, ELAPSED_CPU_PERCENTAGE FROM TABLE( QSYS2.ACTIVE_JOB_INFO() ) X ORDER BY ELAPSED_CPU_PERCENTAGE DESC FETCH FIRST 20 ROWS ONLY
In short, UDTFs are used in similar fashion to RPG’s service programs, which hide complexity and provide reusability. In this case, there are likely many things going on under the covers of
ACTIVE_JOB_INFO, but we only care about the inbound and outbound parameters. For this example, we provide no input (which would allow us to further filter results) and instead specify result columns we need for the web page we’re creating. The
ORDER BY clause is sorting by
ELAPSED_CPU_PERCENTAGE because one of my primary uses of
WRKACTJOB is to see who’s hogging the machine. I used the
STRSQL 5250 command to test the above SQL and honed it to meet the needs of the web application.
Now that we’ve resolved the DB2 for i Service syntax, it’s time to implement it within the existing IBM i Dash open-source project. Note that you can feel free to add your own dashboard pages by “forking” the project, as detailed on the IBM i Dash README.md file.
I used a Litmis Space to accomplish this feature, which required that I copy my SSH public key from my home directory to my Bitbucket.org profile so I could perform the below
git clone command. You can get full details on how to obtain your SSH public key and place it on Bitbucket in [[this article (Git to Bitbucket)]].
The below two commands will copy the ibmidash project down to your development environment and place you into the immediate project’s directory with the
cd (change directory) command.
% git clone email@example.com:litmis/ibmidash.git % cd ibmidash
Note: whenever you see the percent symbol (%), it means you’re in a PASE shell. An alternative is to use
CALL QP2TERM to enter these commands.
Included in the ibmidash project is file
package.json. This holds a variety of items, which include module dependencies for this project—in this case ExpressJs and Jade. We don’t yet have those modules installed in this environment, so it’s necessary to run
npm install, as shown below.
% npm install
Next we need to install the
socket.io module and save it to the
package.json file using the below command.
% npm install socket.io --save
At this point, we have everything installed that’s necessary to complete the programming. One of the nice things about storing code in git on Bitbucket is the ability to easily see changes done across an entire project to learn what was affected. Here is a link to the changes I made that we will now walk through.
Below is a screenshot of the changes made to
index.js, in which red highlights denote removing lines and green adding lines. The first relevant change is on line 3, where the
socket.io module is being brought into our program. Think of this as being similar to doing an RPG
/copy to bring in outside functionality.
The next change is adding route
app.get('wrkactjob', …). This will render the
views/wrkactjob.jade file to the browser. We’ll cover its contents later. The key server-side bit of code is line 65 through 74. The
setInterval function is a means to emit updates to WebSocket event listeners every two seconds (line 74 is 2000 milliseconds). The value being emitted is the result of the call to
ACTIVE_JOB_INFO(), as detailed on line 68. Line 72 is where the emitting actually happens, and it’s sending this message only for those clients listening for the particular event ID of
Figure 2 shows the changes to
header.jade. In this case, we needed to include reference to the client-side socket.io code so it could be downloaded from the Content Delivery Network (CDN). A new menu item was also added so users can navigate to the new page. Note how the link in the anchor (a) tag matches the route in
index.js we mentioned earlier so inbound requests will deliver the
wrkactjob.jade file to the browser.
Figure 3 shows the new
wrkactjob.jade that’s delivered down to the browser. Of initial interest is the table being composed, which contains an empty
tbody. That’s because the app will subsequently fill it with data from the WebSocket after the page loads.
'wrkactjob_update' being emitted from the server. Upon receiving an event from the server, jQuery will be used to iterate over the result set and concatenate a new set of table rows. Then
$("#jobs tbody").html(tbl_body) is used to select and update the
tbody tag’s contents.
We’ve now seen the code changes, and it’s time to see the application in action. Starting the application is as simple as running
node index.js, as shown below.
% node index.js Connect to *LOCAL Connected to *LOCAL with ID , password: . listening on *:8000 SQL: SELECT JOB_NAME, AUTHORIZATION_NAME, ELAPSED_TOTAL_DISK_IO_COUNT, ELAPSED_CPU_PERCENTAGE FROM TABLE(QSYS2.ACTIVE_JOB_INFO()) X ORDER BY ELAPSED_CPU_PERCENTAGE DESC FETCH FIRST 20 ROWS ONLY
When the app is running, you’ll see the SQL statement repeated in the console because database debugging is turned on at the top of
Figure 4 shows the application running. A still image doesn’t really do it justice. The entire table actually updates every two seconds, which is pretty cool! At the bottom of Figure 4 is the Chrome developer console with the Elements tab displayed. In this case, the
tr tags are highlighted because they were just recently updated.
In conclusion, there are undoubtedly many other DB2 for i Services that could make use of this same WebSocket scenario (e.g., NETSTAT_INFO). It’s my hope that others in the community will take on my challenge to contribute additional features to this project!
What ideas do you have for enhancing the IBM i Dash project?
Let’s start a conversation and talk through the possibilities! Reach me directly at firstname.lastname@example.org.
Looking to adopt Node.js on your IBM i? We can help. Contact us below.