Prudence
The Scalable REST/JVM
Web Development Platform

Creative Commons License

Tasks

Programming multi-threaded and distributed applications is usually very difficult, but Prudence makes a lot of the work easier via support for tasks, which run in the "background" outside of the client thread pool, and indeed can run anywhere in your Prudence cluster. Tasks are an important part of your scaling strategy as they allow your application to do work without holding up client threads. For a full discussion, see "Scaling Tips".
Tasks are straightforward scripts placed in the application's /tasks/ subdirectory. They are straightforward in that, upon execution, the code is simply run as is. There is no particular entry point as with /resources/ or /handlers/. They can be run on-demand or scheduled to run at specific times and locations.
Tasks are part of an application, and have access to the same "application", "document" and "executable" API services as other application code. Likewise, you can access any code in /libraries/ via document.execute or via your language's usual inclusion facility. Unlike /resources/ and /web/dynamic/ code, /tasks/ code has no "conversation" API service.
The modern JVM, running on modern operating systems and multi-core hardware, will do a very good job at multi-threading, so be confidence in using /tasks/ heavily.
Prudence provides two facilities for scheduling tasks:

On Demand

Use application.task to spawn or schedule tasks on demand from your /resources/ or /web/dynamic/ code, or application.distributedTask to spawn tasks in your Prudence cluster.
In some cases, you may want to atomically update a boolean in application.globals or application.distributedGlobals to flag that the task has been scheduled, so that you won't schedule it more than once.

At Startup

Startup Task

Prudence will automatically spawn the task called "/startup/" upon startup. Note that it will run after all the other startup tasks (defrosting, preheating) finish, in order to make sure your application is "hot" first. If you need multiple tasks running—usually repeating tasks, such as those that do general maintenance, monitor resource availability, send out email reminders, etc.—you can start them from your startup task using application.task.
For example, here is an application's "/tasks/startup.js" file:
application.logger.info('Scheduling monitor task to repeat every second')
application.task(null, '/monitor/', null, null, 1000, 1000, false) 
Note that this initial run of the "/startup/" task will send the string "initial" for the document.context. This is so you can distinguish between this initial run and possible subsequent runs that you spawn yourself.

Custom Startup Tasks

You can also use application.task to schedule general tasks in any of the application's configuration scripts.
Here is an example "default.js" (note the use of "applicationService" instead of "application"):
document.execute('/defaults/application/')
​
applicationService.task(null, '/poll/', null, {name: 'mypoll', maxDuration: 5000}, 1000, 1000, false) 

crontab

This facility lets you schedule tasks to run at specific (Gregorian) calendrical times. It is similar to calling application.task in the application's configuration scripts, but allows for more succinct, calendrical repetition patterns.
To use this facility, place a file with the name "crontab" in your application's base subdirectory. Its format is purposely very similar to that of the crontab configuration file found in many Unix-like operating system: each line starts with scheduling pattern and ends with the task name.
Optionally, you may add more text after the task name and whitespace: anything there is grabbed as a single string and sent as the context to the task, which can be accessed there as document.context. Because crontab is a text file, only textual contexts may be sent, but you can use JSON, XML or other encodings to create complex contexts.
The scheduling pattern is a series of five whitespace-separated settings. Any of these settings can be "*", signifying that any value would match. Use a slash to match only numbers that divide equally by the number after the slash (can also be used on "*"). Ranges (inclusive) are possible, separated by hyphens. Multiple settings are possible, separated by commas. Multiple patterns are possible, separated by pipes.
  1. Minutes of the hour, 0-59.
  2. Hour of the day, 0-23.
  3. Day of the month, 1-31. The special setting "L" signifies the last day of the month, which varies per month and year.
  4. Month of the year, 1-12. Three-letter English month names may be used instead of numbers: "jan", "feb", "mar", etc.
  5. Day of the week, 0-6. Three-letter English day names may be used instead of numbers: "sun", "mon", "tue", etc.
Example patterns:
  • Every minute: * * * * *
  • 11:59pm every Tuesday and Friday: 59 23 * * tue,fri
  • Every 5 minutes in the morning, between 5 to 8am, otherwise every 30 minutes: */5 5-7 * * *|*/30 0-4,8-23 * * *
  • The same as above, but with one added to all minutes of the hour: 1,6,11,16,21,26,31,36,41,46,51,56 5-7 * * *|1,31 0-4,8-23 * * *
Notes:
  1. "crontab" will be checked for changes and parsed once per minute. This means that you can edit this file and have your task scheduling change on the fly without restarting Prudence.
  2. You can schedule the same task on multiple lines, which is not equivalent to using the pipe: multiple lines means that multiple task instances might be spawned simultaneously if matched on more than one line. Contrarily, using the pipe counts as a single match.
  3. The scheduler does not check to see if a task finished running before spawning a new instance of it, so that even if a task is not done yet, but it's time for it to be spawned again, you'll have multiple instances of the task running at the same time. If this is problematic, consider using application.task in your configuration scripts instead, with "false" as the last argument.
You can also set up a special crontab to run arbitrary Java static methods and even non-JVM system processes. Internally, Prudence uses the flexible cron4j library. See its documentation for more information. Here's an example application's "default.js" configuration script to set up a "crontab-system" file:
document.execute('/defaults/application/')
scheduler.scheduleFile(new File(applicationBasePath + '/crontab-system'))