...
Clowder supports scheduling of repetitive tasks by executing a job registered in MongoDB jobs
Collection called jobs.
The only implemented job as of August 2016 is EmailDigest
triggered by setting an e-mail option in user's profile page as seen in Figure below. Selecting hourly, daily or monthly option in the pull down menu creates a job called Digest('iduserId')
in the database which is then executed at pre-defined times, currently at the top of an hour (hourly), at 7:00 am (daily) or every Monday at 7:00 am (weekly).
...
Create function
getMyJobs()
inapp/models/JobsScheduler.scala
to get your job (TimerJob
) at a certain timeCode Block language scala def getMyJobs (minute: Integer, hour: Integer, day_of_week: Integer) = { var myJobs = scheduler.getJobByTime(minute, hour, day_of_week) myJobs }
and register it with
runScheduledJobs()
Code Block language scala var myJobs = getMyJobs(minute.toInt, hour.toInt, day_of_week.toInt) myAction.myActionJob(myJobs)
Create a new class
myAction.scala
for example in a packagemodels
(seemodels/Event.scala
as an example)Code Block language scala collapse true package models import java.util.Date import services.SchedulerService import services.DI object myAction { val scheduler: SchedulerService = DI.injector.getInstance(classOf[SchedulerService]) val objects: ObjectService = DI.injector.getInstance(classOf[ObjectService]) /** * ‘Do something’ for each job returned by getMyJobs */ def myActionJob(listJob: List[TimerJob]) = { for (job <- listJob){ job.parameters match { case Some(id) => { objects.findById(id) match { case Some(object) => { job.lastJobTime match { case Some(date) => { ‘Do something’ } case None => Logger.debug("LastJobTime not found") } } case None => Logger.debug(“Object not found") } scheduler.updateLastRun(‘jobName’) //sets job’s name for example ”myJob[“ + id + "]") } case None => Logger.debug("Parameters not found") } } }
The
ObjectService
above, for example calledUserService
in the case of sending email digest and the user id was used as a parameter in theTimerJob
and MongoDB job objects.implement
'Do something'
inmyActionmyActionJob()
Note
The day_of_month
variable is part of the TimerJob
model but it is not used in the scheduler.getJobByTime()
Adding it is straightforward:
app/services/SchedulerService.scala
Code Block language scala collapse true def getJobByTime(minute: Integer, hour: Integer, day_of_week: Integer, day_of_month: Integer): List[TimerJob]
app/services/mongoldb/MongoDBSchedulerService.scala
Code Block language scala collapse true def getJobByTime(minute: Integer, hour: Integer, day_of_week: Integer, day_of_month: Integer): List[TimerJob] ={ val jobs = Jobs.find( $and( // either day_of_month exists AND the value is 'day_of_month' OR day_of_month does not exist $or($and("day_of_month" $exists true, MongoDBObject("day" -> day_of_month)), "day_of_month" $exists false), // either day_of_week exists AND the value is 'day_of_week' OR day_of_week does not exist $or($and("day_of_week" $exists true, MongoDBObject("day_of_week" -> day_of_week)), "day_of_week" $exists false), // either hour exists AND the value is 'hour' OR hour does not exist $or($and("hour" $exists true, MongoDBObject("hour" -> hour)), "hour" $exists false), // either minute exists AND the value is 'minute' OR minute does not exist $or($and("minute" $exists true, MongoDBObject("minute" -> minute)), "minute" $exists false) ) )
Code Block language scala collapse true def updateJobTime(name: String, minute: Option[Integer], hour: Option[Integer], day_of_week: Option[Integer], day_of_month: Option[Integer], freq: Option[String]) = { if (minute == None){ Jobs.dao.update(MongoDBObject("name" -> name), $unset("minute")) } else { Jobs.dao.update(MongoDBObject("name" -> name), $set("minute" -> minute)) } if (hour == None){ Jobs.dao.update(MongoDBObject("name" -> name), $unset("hour")) } else { Jobs.dao.update(MongoDBObject("name" -> name), $set("hour" -> hour)) } if (day_of_week == None){ Jobs.dao.update(MongoDBObject("name" -> name), $unset("day_of_week")) } else { Jobs.dao.update(MongoDBObject("name" -> name), $set("day_of_week" -> day_of_week)) } if (day_of_month == None){ Jobs.dao.update(MongoDBObject("name" -> name), $unset("day_of_month")) } else { Jobs.dao.update(MongoDBObject("name" -> name), $set("day_of_month" -> day_of_month)) } Jobs.dao.update(MongoDBObject("name" -> name), $set("frequency" -> freq)) }
add extra parameter (
None
) toupdateEmailJob()
Testing
...
Add functioning e-mail in app/util/Mail.scala
if you use a 'fake' e-mail in your local Clowder developmental branch
Code Block | ||||
---|---|---|---|---|
| ||||
def sendEmail(subject: String, user: Option[User], recipient: User, body: Html) {
if (recipient.email.isDefined) {
Logger.debug("Subject:" + subject + ", From:" + emailAddress(user) + ", Recipient: " + emailAddress(Some(recipient)) + ", Body:")
//sendEmail(subject, emailAddress(user), emailAddress(Some(recipient))::Nil, body)
sendEmail(subject, emailAddress(user), List("yourEMail@illinois.edu"), body)
}
} |
Use functioning smtp
in securesocial.conf
or override it by setting smtp.host
and (optional) smtp.from
in your custom.conf
Code Block | ||
---|---|---|
| ||
smtp.host=smtp.ncsa.illinois.edu
smtp.from=yourEMail@illinois.edu |
...
- Disable
scheduler.updateLastRun(‘jobName’)
inmyAction.scala
(or inmodels/Event.scala
for sending email digests) by commenting it out. Your events (followed objects for example) will become 'permanent' and the timer job will always execute since there is no update of thelastJobTime
variable in the MongoDB job object. Don't forget to enable theupdateLastRun()
when you are done debugging. Set the time variables in
getJobByTime() in app/services/mongoldb/MongoDBSchedulerService.scala
to those saved in the MongoDB job object. The job action will fire every minute since the integer equality is always true. For example for the pre-defined e-mail times (minute
=0,hour
=7 andday_of_week
=1) setgetJobByTime()
Code Block language scala def getJobByTime(minute: Integer, hour: Integer, day_of_week: Integer, day_of_month: Integer): List[TimerJob] ={ val jobs = Jobs.find( $and( $or($and("day_of_week" $exists true, MongoDBObject("day_of_week" -> 1)), "day_of_week" $exists false), $or($and("hour" $exists true, MongoDBObject("hour" -> 7)), "hour" $exists false), $or($and("minute" $exists true, MongoDBObject("minute" -> 0)), "minute" $exists false) ) )
Again, don't forget to reverse changes when you are done debugging.
Testing e-mail digest
Add functioning e-mail in
app/util/Mail.scala
if you use a 'fake' e-mail in your local Clowder developmental branchCode Block language scala collapse true def sendEmail(subject: String, user: Option[User], recipient: User, body: Html) { if (recipient.email.isDefined) { Logger.debug("Subject:" + subject + ", From:" + emailAddress(user) + ", Recipient: " + emailAddress(Some(recipient)) + ", Body:") //sendEmail(subject, emailAddress(user), emailAddress(Some(recipient))::Nil, body) sendEmail(subject, emailAddress(user), List("yourEMail@illinois.edu"), body) } }
Use functioning
smtp
insecuresocial.conf
or override it by settingsmtp.host
and (optional)smtp.from
in yourcustom.conf
Code Block language scala smtp.host=smtp.ncsa.illinois.edu smtp.from=yourEMail@illinois.edu
Note that the host above can be used only within the NCSA's network
Set the time variables in getJobByTime() in app/services/mongoldb/MongoDBSchedulerService.scala
to those saved in the MongoDB job object. The job action will fire every minute since the integer equality is always true. For example for the pre-defined e-mail times (minute
=0, hour
=7 and day_of_week
=1) set getJobByTime()
Code Block | ||
---|---|---|
| ||
def getJobByTime(minute: Integer, hour: Integer, day_of_week: Integer, day_of_month: Integer): List[TimerJob] ={
val jobs = Jobs.find(
$and(
$or($and("day_of_week" $exists true, MongoDBObject("day_of_week" -> 1)), "day_of_week" $exists false),
$or($and("hour" $exists true, MongoDBObject("hour" -> 7)), "hour" $exists false),
$or($and("minute" $exists true, MongoDBObject("minute" -> 0)), "minute" $exists false)
)
) |
...
.