Visual Report Writer and The Web (III)¶
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 series.
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 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 publicly 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 large, and many files will no longer be 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 session key and can be made to expire by setting a timeout specified in hours. By default, the timeout is set to 0, which means infinite. 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 session key, it is not advised to do so; otherwise, anyone can copy the URL and pass it to someone else, allowing them to read the file contents.
Cleanup¶
I see three ways to clean up the cache folder. They are:
- A program that performs the cleanup started by the Windows scheduler. This may even be a batch file.
- Part of the web server backup plan. Of course, you have your schedule to back up the data on the server, and the cleanup could be done as part of that activity.
- 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 clean up, the process should not make your web application slower. To avoid this, I made the cleanup in the live demo website operate once for every 50 requests received by one of the web applications in the pool. There is no timer at the web server itself, and this counter-based activity sounds okay 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
End_Procedure
End_Object
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, which 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 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
Repeat
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
End
End
Move (winFindNextFile(hFindFile, AddressOf(FileData))) to iRetval
Until (iRetval = 0)
Move (winFindClose(hFindFile)) to iRetval
End
Move 0 to iAccessed
End
Set piAccessed to iAccessed
End_Procedure
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 and winFindNextFile functions 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.