View RSS Feed

Development Team Blog

Visual Report Writer and The Web (III)

Rate this Entry
This is the third blog about Visual Report Writer and the Web. Did you already digest the other two blogs (Solution Page and Invoices Report)? If not, I suggest you read them first. This blog is about cleanup at the server. It is not the last one in the serie.

Cache files
From the blog about Invoices Report you should have learned that the integration library instructs Visual Report Writer to create a PDF file with the output of the report. By default this output file is only for the current session and can be made only available for a certain amount of time. The output is stored in a cache folder. The standard output folder is named Cache and resides inside the Reports folder. The cache folder does not have to be a sub-folder of the reports folder but it is by default and it is advisable as This folder is not web shared and files are not public accessible. The function ReportCacheFileName (member of the cVRWReport class) creates a unique file name in the cache folder. Certainly if a lot of users/sessions create reports the cache folder will soon be big and a lot of files are no longer accessible. How long should the files in there be kept? Who should be responsible for cleanup?

The files should be available as long as the URL that is generated can be used. The URL generated by the cWebResourceManager can be bound to the sessionkey and can be made to expire by setting a timeout specified in hours. By default the timeout is set to 0 which means infinitive. If you want to have the URL not available for that time span you have to set the piDownloadTimeout property of the ghoWebResourceManager object. You can do this globally or per report but keep in mind that the value is always global and if not set again will be applied for the next URL. While it is possible to not bind the URL to the current sessionkey it is not advised to do so else anyone can copy the URL and pass it to someone else and they can read the file contents.

i see three ways to cleanup the cache folder. They are:
  • Program that performs the cleanup started by the Windows scheduler. This may even be a batch file.
  • Part of the webserver backup plan. Of course you have your schedule to backup the data on the server and the cleanup could be done as part of that activity.
  • Have a routine inside your web application that periodically cleans the cache folder. This option is discussed here in this blog as it is in use for the Visual Report Writer Live Demo website.
Cleanup routine inside your application
While it is important to cleanup the process should not make your web application slower. To avoid this happens I made the cleanup in the live demo website to operate once in each 50 times that a request is received by one of the web applications in the pool. There is not such a thing as timer at the webserver itself and this counter based activity sounds Ok to me. The only downside is that it will be accessed a number of times in a row as each of the applications in the pool uses its own counter. I could have created a shared counter but that requires a bit of I/O that I did not want to use.

I wrote the cleanup routine in a self created object named oVRWReportsManager and since this is not really a web object it is an instance of the cObject class, the most empty class in the product. The cleanup routine is invoked from OnAttachProcess in the cWebApp object.
    Procedure OnAttachProcess
        Forward Send OnAttachProcess
        Send Cleanup of oVRWReportsManager

Send StartWebApp of oWebApp
The above code snippet is the bottom part of the cWebApp object in WebApp.src. The routine does not need to be at the bottom but it just is.

In the cVRWReportsManager object I defined a regular DataFlex property named piAccessed and it is incremented by the message Cleanup. As soon as it becomes 50 or higher the cleanup starts and the property is set back to zero. If 50 would be too often it could be easily changed.

When the counter hits 50 the current date and time is retrieved via a CurrentDateTime() function and the cache folder is enumerated with Windows API functions to see if there are files that are older than 180 minutes. If they are the files are deleted. The following code does do this.
Procedure Cleanup
    Integer iAccessed iRetval iMinutes
    String sCachePath sFileName
    Handle hFindFile
    tWin32_Find_Data FileData
    DateTime dtNow dtCreated
    TimeSpan tsDiff
    Get piAccessed to iAccessed
    Increment iAccessed
    If (iAccessed > 50) Begin
        Move (CurrentDateTime ()) to dtNow
        Get ReportsCacheFolder of oVRWReport to sCachePath
        Move (winFindFirstFile (sCachePath - '*.*', AddressOf (FileData))) to hFindFile
        If (hFindFile <> INVALID_HANDLE_VALUE) Begin
                If (not (IsFlagIn (FILE_ATTRIBUTE_DIRECTORY, FileData.dwFileAttributes))) Begin
                    Get ConvertDateTimeToSystemDateTime FileData.ftCreationLowDateTime FileData.ftCreationHighDateTime to dtCreated
                    Move (dtNow - dtCreated) to tsDiff
                    Move (SpanTotalMinutes (tsDiff)) to iMinutes
                    If (iMinutes > 180) Begin
                        Move (AddressOf (FileData.cFileName)) to sFileName
                        Move (sCachePath - sFileName) to sFileName
                        Move (DeleteFile (AddressOf (sFileName))) to iRetval
                Move (winFindNextFile (hFindFile, AddressOf (FileData))) to iRetval            
            Until (iRetval = 0)
            Move (winFindClose (hFindFile)) to iRetval
        Move 0 to iAccessed
    Set piAccessed to iAccessed
The ConvertDateTimeToSystemDateTime is not a built in routine but a function I wrote a long time ago (1999/2000) and published via the Data Access knowledge base. The winFindFile, winFindNextFile function are defined in the cWorkspace.pkg file.

I hope this blog helps you further on your path to use the DataFlex Web Framework in combination with Visual Report Writer.