Justin James describes how simple it is to create scheduled tasks (or Timers) in the OutSystems Agile Platform. You can set a Timer's schedule, priority, action, and more.
Read the previous installments in the series: Getting started with the OutSystems Agile Platform, Learning the basics of the OutSystems Agile Platform, Describing the OutSystems Agile Platform Service Studio experience, Working with the OutSystems Agile Platform's Integration Studio, Deploying an application created with the OutSystems Agile Platform, and Adding ECT to an eSpace with the OutSystems Agile Platform.
One of Rat Catcher's major differentiators compared to similar products is the idea that it can create a report on a regular basis that shows the user where their documents have appeared on the Internet. Scheduling tasks in Web-based applications is not usually the most pleasant thing in the world.
One way to do it is to completely separate your application from the logic so that you can write a lightweight application to handle the scheduled tasks and call it on a schedule. Another approach is to write a service or a daemon that has a scheduling component. Alternatively, you can put the code in a Web page and call that page from the operating system's scheduler. Some systems use a "poor man's cron," where when a page is called in the application and there are pending tasks to be run, a secondary process is launched to run the tasks. But no matter how you look at it, the traditional options for having batch processing are not appealing and require additional configuration. In the Agile Platform, task scheduling is built-in and using it is a smooth and natural extension of the rest of the work.In the Agile Platform, scheduled tasks are known as Timers. Creating a Timer is very easy. In the eSpace's tree, there is a node for them, and you create a new one like you would any other new item in the eSpace. The Timer has some properties (Figure A) that you will want to set to ensure that it works the way you need it to:
- Schedule: This controls how frequently the Timer performs the associated Action.
- Priority: If there are multiple Timers scheduled for the same time, the Priority attribute determines which ones take precedence.
- Action: This determines what will happen when the Timer is fired; if you choose an Action with arguments, you will be able to set those as well.
- Timeout in Minutes: A Timer can be set with a Timeout, so the scheduling system knows to cancel it if it has run for too long.
The properties of my SendQuotaEmails Timer.One disappointment is that your scheduling options are fairly simplistic (Figure B). OutSystems has recently asked the community for feedback, and improving the scheduling was on the list of things that people have suggested (you must log in to access this page). Figure B
The Timer schedule options are adequate, but they could be a bit more in-depth.For my current needs, I will create two Timers. The first Timer will look at all of the user accounts, find out how many documents are going on their schedule, see if they are close to their limit, and send the account administrator a "heads up" email. What makes this Action work well is that I added a Boolean attribute to my entity for accounts that indicates if an over quota email had been sent (Figure C). When I do send an email, I set this attribute to True. Any accounts that are currently under the quota have this flag set to False. I also modified my account upgrade process to reset this attribute to False; that way, the emails are only sent once, but will always be sent once an account is over quota. Figure C
The Action that handles sending "over quota" emails.
On a side note, the Envelope icon in Figure C is to send an email message, which is one of the very nice features of the Agile Platform. In some systems I have used, you need to create email templates and then populate a collection of values and have the email template filled with macros to substitute values from the collection. In the Agile Platform, you design an email just like a Web page, and it can have its own logic and accept parameters as needed. In this case, my email message takes the account's ID as an argument and has a Preparation Action that looks up all of the needed information to fill out the email. Within the email, you use the same Widgets that you use for the Web screens to display the data you pull. As a result, working with emails is very pleasant and consistent with the rest of the system.The second Timer will run the nightly reports (Figure D). This was pretty easy to do. First, I loop through all of the accounts and look for accounts that have the current day as their day of the month to run reports. The way I handle reports is that I generate a REPORT entity with all of the needed information with a list of JOB_TASK entities (each one represents a document and its related settings) associated with the REPORT. For the scheduled reports, I copy the information for the JOB_TASKs from a SCHEDULED_JOB_TASK entity, which is what the user manipulates when they edit their scheduled reports; this way, archived reports show the settings that were used to run the report, not the currently selected settings. Once the REPORT entity is created, I call the same RunReport function that I call when a user runs an ad-hoc report. Finally, I email the account administrator and let him or her know that the report was run and include a link to the report. Figure D
The RunScheduledReports Action is pretty straightforward.
I may create a third Timer to perform the monthly billing. Some credit card gateways can perform recurring billing automatically. If I were to allow the gateway to handle the recurring billing, it would take a bit of the load off of my back in terms of worrying about storing credit card numbers and the associated security concerns with that. It is not that I do not trust myself or the Agile Platform, it is a simple matter of risk mitigation. Why store sensitive data and make yourself a target for hackers if you can help it? But if I allow the credit card gateway to handle the recurring billing, I will need to add gobs of logic to change the billing information as users upgrade and downgrade accounts; it would definitely be far less effort to just have a billing Action that pulls the proper number on a monthly basis and charges that. And, I already have this logic built into my ACCOUNT entity anyway.
I will be making a decision about this third Timer soon. The billing situation, the overall "look and feel," and making the system self-explanatory are my big remaining challenges before I can start marketing Rat Catcher as a full-blown product.
J.JaDisclosure of Justin's industry affiliations: Justin James has a contract with Spiceworks to write product buying guides; he has a contract with OpenAmplify, which is owned by Hapax, to write a series of blogs, tutorials, and articles; and he has a contract with OutSystems to write articles, sample code, etc.