All Downloads are FREE. Search and download functionalities are using the official Maven repository.

monix.execution.Scheduler.scala Maven / Gradle / Ivy

/*
 * Copyright (c) 2014-2016 by its authors. Some rights reserved.
 * See the project homepage at: https://monix.io
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package monix.execution

import java.util.concurrent.TimeUnit
import monix.execution.internal.RunnableAction
import monix.execution.schedulers.ExecutionModel
import monix.execution.schedulers.SchedulerCompanionImpl
import scala.annotation.implicitNotFound
import scala.concurrent.ExecutionContext
import scala.concurrent.duration.FiniteDuration
import scala.language.experimental.macros

/** A Scheduler is an `scala.concurrent.ExecutionContext` that additionally can
  * schedule the execution of units of work to run with a delay or periodically.
  */
@implicitNotFound(
  "Cannot find an implicit Scheduler, either " +
  "import monix.execution.Scheduler.Implicits.global or use a custom one")
abstract class Scheduler extends ExecutionContext with UncaughtExceptionReporter {
  /** Schedules the given `runnable` for immediate execution. */
  def execute(runnable: Runnable): Unit

  /** Reports that an asynchronous computation failed. */
  def reportFailure(t: Throwable): Unit

  /** Schedules a task to run in the future, after `initialDelay`.
    *
    * For example the following schedules a message to be printed to
    * standard output after 5 minutes:
    * {{{
    *   val task = scheduler.scheduleOnce(5, TimeUnit.MINUTES, new Runnable {
    *     def run() = print("Hello, world!")
    *   })
    *
    *   // later if you change your mind ...
    *   task.cancel()
    * }}}
    *
    * @param initialDelay is the time to wait until the execution happens
    * @param unit is the time unit used for `initialDelay`
    * @param r is the callback to be executed
    * @return a `Cancelable` that can be used to cancel the created task
    *         before execution.
    */
  def scheduleOnce(initialDelay: Long, unit: TimeUnit, r: Runnable): Cancelable

  /** Schedules for execution a periodic task that is first executed
    * after the given initial delay and subsequently with the given
    * delay between the termination of one execution and the
    * commencement of the next.
    *
    * For example the following schedules a message to be printed to
    * standard output every 10 seconds with an initial delay of 5
    * seconds:
    * {{{
    *   val task = s.scheduleWithFixedDelay(5, 10, TimeUnit.SECONDS, new Runnable {
    *     def run() = print("Repeated message")
    *   })
    *
    *   // later if you change your mind ...
    *   task.cancel()
    * }}}
    *
    * @param initialDelay is the time to wait until the first execution happens
    * @param delay is the time to wait between 2 successive executions of the task
    * @param unit is the time unit used for the `initialDelay` and the `delay` parameters
    * @param r is the callback to be executed
    * @return a cancelable that can be used to cancel the execution of
    *         this repeated task at any time.
    */
  def scheduleWithFixedDelay(initialDelay: Long, delay: Long, unit: TimeUnit, r: Runnable): Cancelable

  /** Schedules a periodic task that becomes enabled first after the given
    * initial delay, and subsequently with the given period. Executions will
    * commence after `initialDelay` then `initialDelay + period`, then
    * `initialDelay + 2 * period` and so on.
    *
    * If any execution of the task encounters an exception, subsequent executions
    * are suppressed. Otherwise, the task will only terminate via cancellation or
    * termination of the scheduler. If any execution of this task takes longer
    * than its period, then subsequent executions may start late, but will not
    * concurrently execute.
    *
    * For example the following schedules a message to be printed to standard
    * output approximately every 10 seconds with an initial delay of 5 seconds:
    * {{{
    *   val task = scheduler.scheduleAtFixedRate(5, 10, TimeUnit.SECONDS, new Runnable {
    *     def run() = print("Repeated message")
    *   })
    *
    *   // later if you change your mind ...
    *   task.cancel()
    * }}}
    *
    * @param initialDelay is the time to wait until the first execution happens
    * @param period is the time to wait between 2 successive executions of the task
    * @param unit is the time unit used for the `initialDelay` and the `period` parameters
    * @param r is the callback to be executed
    * @return a cancelable that can be used to cancel the execution of
    *         this repeated task at any time.
    */
  def scheduleAtFixedRate(initialDelay: Long, period: Long, unit: TimeUnit, r: Runnable): Cancelable

  /** Returns the current time in milliseconds.  Note that while the
    * unit of time of the return value is a millisecond, the
    * granularity of the value depends on the underlying operating
    * system and may be larger.  For example, many operating systems
    * measure time in units of tens of milliseconds.
    *
    * It's the equivalent of `System.currentTimeMillis()`. When wanting
    * to measure time, do not use `System.currentTimeMillis()`
    * directly, prefer this method instead, because then it can be
    * mocked for testing purposes (see for example
    * [[monix.execution.schedulers.TestScheduler TestScheduler]])
    */
  def currentTimeMillis(): Long

  /** The [[monix.execution.schedulers.ExecutionModel ExecutionModel]]
    * is a specification of how run-loops and producers should behave
    * in regards to executing tasks either synchronously or
    * asynchronously.
    */
  def executionModel: ExecutionModel
}

private[monix] trait SchedulerCompanion {
  trait ImplicitsLike {
    def global: Scheduler
  }

  def Implicits: ImplicitsLike
  def global: Scheduler
}

object Scheduler extends SchedulerCompanionImpl {
  self: SchedulerCompanion =>

  /** Utilities complementing the `Scheduler` interface. */
  implicit final class Extensions(val source: Scheduler) extends AnyVal {
    /** Schedules the given callback for immediate asynchronous
      * execution in the thread-pool.
      *
      * Described as a macro, thus it has zero overhead compared
      * to doing `execute(new Runnable { ... })`
      *
      * @param cb the callback to execute asynchronously
      */
    def executeAsync(cb: => Unit): Unit =
      macro Macros.executeAsync

    /** Schedules the given callback for immediate execution as a
      * [[monix.execution.schedulers.LocalRunnable LocalRunnable]].
      * Depending on the execution context, it might
      * get executed on the current thread by using an internal
      * trampoline, so it is still safe from stack-overflow exceptions.
      *
      * Described as a macro, thus it has zero overhead compared
      * to doing `execute(new LocalRunnable { ... })`
      *
      * @param cb the callback to execute asynchronously
      */
    def executeLocal(cb: => Unit): Unit =
      macro Macros.executeLocal

    /** Schedules a task to run in the future, after `initialDelay`.
      *
      * For example the following schedules a message to be printed to
      * standard output after 5 minutes:
      * {{{
      *   val task = scheduler.scheduleOnce(5.minutes) {
      *     print("Hello, world!")
      *   }
      *
      *   // later, if you change your mind ...
      *   task.cancel()
      * }}}
      *
      * @param initialDelay is the time to wait until the execution happens
      * @param action is the callback to be executed
      * @return a `Cancelable` that can be used to cancel the created task
      *         before execution.
      */
    def scheduleOnce(initialDelay: FiniteDuration)(action: => Unit): Cancelable =
      source.scheduleOnce(initialDelay.length, initialDelay.unit, RunnableAction(action))

    /** Schedules for execution a periodic task that is first executed
      * after the given initial delay and subsequently with the given
      * delay between the termination of one execution and the
      * commencement of the next.
      *
      * For example the following schedules a message to be printed to
      * standard output every 10 seconds with an initial delay of 5
      * seconds:
      * {{{
      *   val task = s.scheduleWithFixedDelay(5.seconds, 10.seconds) {
      *     print("Repeated message")
      *   }
      *
      *   // later if you change your mind ...
      *   task.cancel()
      * }}}
      *
      * @param initialDelay is the time to wait until the first execution happens
      * @param delay is the time to wait between 2 successive executions of the task
      * @param action is the callback to be executed
      * @return a cancelable that can be used to cancel the execution of
      *         this repeated task at any time.
      */
    def scheduleWithFixedDelay(initialDelay: FiniteDuration, delay: FiniteDuration)
      (action: => Unit): Cancelable = {

      source.scheduleWithFixedDelay(initialDelay.toMillis, delay.toMillis, TimeUnit.MILLISECONDS,
        RunnableAction(action))
    }

    /** Schedules a periodic task that becomes enabled first after the given
      * initial delay, and subsequently with the given period. Executions will
      * commence after `initialDelay` then `initialDelay + period`, then
      * `initialDelay + 2 * period` and so on.
      *
      * If any execution of the task encounters an exception, subsequent executions
      * are suppressed. Otherwise, the task will only terminate via cancellation or
      * termination of the scheduler. If any execution of this task takes longer
      * than its period, then subsequent executions may start late, but will not
      * concurrently execute.
      *
      * For example the following schedules a message to be printed to standard
      * output approximately every 10 seconds with an initial delay of 5 seconds:
      * {{{
      *   val task = scheduler.scheduleAtFixedRate(5.seconds, 10.seconds) {
      *     print("Repeated message")
      *   }
      *
      *   // later if you change your mind ...
      *   task.cancel()
      * }}}
      *
      * @param initialDelay is the time to wait until the first execution happens
      * @param period is the time to wait between 2 successive executions of the task
      * @param action is the callback to be executed
      * @return a cancelable that can be used to cancel the execution of
      *         this repeated task at any time.
      */
    def scheduleAtFixedRate(initialDelay: FiniteDuration, period: FiniteDuration)
      (action: => Unit): Cancelable = {

      source.scheduleAtFixedRate(initialDelay.toMillis, period.toMillis, TimeUnit.MILLISECONDS,
        RunnableAction(action))
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy