Periodic

How it works

Periodic tasks are like Tasks but as the name implies GreyCat will run them periodically once registered.

To register periodic tasks we need to use the runtime module:

use runtime;

task my_task() {
  println("The current time is ${time::now()}");
}

fn main() {
  var my_task_every_day = PeriodicTask {
    user_id: 0,                 // the user associated with the execution
    arguments: null,            // the arguments to use for the execution
    every: 1_day,               // the periodicity as a duration
    function: project::my_task, // the function pointer of the task
    start: time::now(),         // the time of the first execution
  };

  // register the task in the scheduler
  PeriodicTask::set([my_task_every_day]);
}

Note that as of today, the scheduler API is only providing PeriodicTask::set(...) which means you have to always define the whole list of periodic task when calling PeriodicTask::set(...) otherwise the previously registered ones will be unregistered.

Manipulating periodic taskss

Because the API is minimalist, manipulating the current list of registered PeriodicTasks is a bit tedious so here is an example of abstraction above what is currently available in the standard library:

use runtime;

type PeriodicTaskHelper {
  /// Schedules the given task
  static fn schedule(pTask: PeriodicTask) {
    var tasks = PeriodicTask::all();
    tasks.add(pTask);
    PeriodicTask::set(tasks);
  }

  /// Removes the first PeriodicTask from the scheduler and returns it
  ///
  /// If there is no tasks scheduled, `null` is returned.
  static fn shift(): PeriodicTask? {
    var tasks = PeriodicTask::all();
    var pTask: PeriodicTask?;
    if (tasks.size() > 0) {
      pTask = tasks[0];
      tasks.remove(0);
      PeriodicTask::set(tasks);
    }
    return pTask;
  }

  /// Removes the last PeriodicTask from the scheduler and returns it
  ///
  /// If there is no tasks scheduled, `null` is returned.
  static fn pop(): PeriodicTask? {
    var tasks = PeriodicTask::all();
    var len = tasks.size();
    var pTask: PeriodicTask?;
    if (len > 0) {
      pTask = tasks[len];
      tasks.remove(len);
      PeriodicTask::set(tasks);
    }
    return pTask;
  }

  /// Removes the task at the given index.
  ///
  /// Returns `true` on success, otherwise `false`
  static fn remove_at(index: int): bool {
    var tasks = PeriodicTask::all();
    var len = tasks.size();
    if (index >= len) {
      return false;
    }
    tasks.remove(index);
    PeriodicTask::set(tasks);
    return true;
  }

  /// Removes the first task that matches `task.function == ptr`
  ///
  /// Returns `true` on success, otherwise `false`
  static fn remove_first(ptr: function): bool {
    var tasks = PeriodicTask::all();
    for (i, pTask in tasks) {
      if (pTask.function == ptr) {
        tasks.remove(i);
        PeriodicTask::set(tasks);
        return true;
      }
    }
    return false;
  }

  /// Removes the last task that matches `task.function == ptr`
  ///
  /// Returns `true` on success, otherwise `false`
  static fn remove_last(ptr: function): bool {
    var tasks = PeriodicTask::all();
    var len = tasks.size();
    for (var i = len - 1; i >= 0; i--) {
      if (tasks[i].function == ptr) {
        tasks.remove(i);
        PeriodicTask::set(tasks);
        return true;
      }
    }
    return false;
  }
}