Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Clowder supports scheduling of repetitive tasks by executing a job registered in MongoDB jobs Collection

...

. 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('

...

userId') 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). 

Image AddedImplementation

...

  1. Create function getMyJobs() in app/models/JobsScheduler.scala to get your job (TimerJob) at a certain time

    Code Block
    languagescala
    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
    languagescala
    var myJobs = getMyJobs(minute.toInt, hour.toInt, day_of_week.toInt)
    myAction.myActionJob(myJobs)
  2. Create a new class myAction.scala for example in a package models (see models/Event.scala as an example)

    Code Block
    languagescala
    collapsetrue
    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 called UserService in the case of sending email digest and the user id was used as a parameter in the TimerJob and MongoDB job objects.

  3. implement 'Do something' in myActionmyActionJob() (smile)

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
    languagescala
    collapsetrue
    def getJobByTime(minute: Integer, hour: Integer, day_of_week: Integer, day_of_month: Integer): List[TimerJob]
  • app/services/mongoldb/MongoDBSchedulerService.scala

    Code Block
    languagescala
    collapsetrue
    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
    languagescala
    collapsetrue
    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) to updateEmailJob()

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
languagescala
collapsetrue
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
languagescala
smtp.host=smtp.ncsa.illinois.edu
smtp.from=yourEMail@illinois.edu

...

  1. Disable scheduler.updateLastRun(‘jobName’) in myAction.scala (or in models/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 the lastJobTime variable in the MongoDB job object. Don't forget to enable the updateLastRun() when you are done debugging.

  2. 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
    languagescala
    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.

  3. 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 branch

      Code Block
      languagescala
      collapsetrue
      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
      languagescala
      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
languagescala
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)
      )
    )

...

    • .