带有后台任务的Scala命令行应用程序

时间:2015-09-16 23:08:39

标签: multithreading scala background task command-line-interface

我正在使用Scala中的命令行程序。一些命令将产生后台线程以执行一些工作。一些命令将产生线程,这些线程会以一些延迟重复运行相同的任务。我还需要一个停止命令来阻止现有的后台任务重复(不需要杀死它,只是在完成迭代后退出)。构建这种程序的最佳基元是什么?

我正在考虑使用Futures,例如下面。你们对这个设计有什么看法?你会如何实现这种功能?

case class OneTimeTaskCommand(arg: String)
case class StopTaskCommand(name: String)
case class RepeatingTaskCommand(name: String, delay: Long, arg: String)

def runOneTimeTask(arg: String): Unit = { ... }
def runRepeatingTaskCommand(arg: String): Unit = { ... }

trait Scheduler {
    def schedule(name: String, delay: Long): Unit
    def unschedule(name: String): Unit
    def isScheduled(name: String): Boolean = repeatDelay(name).isDefined
    def repeatDelay(name: String): Option[Long]
}

def runCommand(command)(implicit scheduler: Scheduler): Future[Unit] = {
  command match {
    case OneTimeTaskCommand(arg) => Future(runOneTimeTask(arg))
    case StopTaskCommand(name) =>
        if (scheduler.isScheduled(name)) {
            scheduler.unschedule(name)
            Future.successful(())
        } else {
            Future.failure(new CommandException(s"task $name is not running"))
        }
    case RepeatingTaskCommand(name, delay, arg) =>
        /* function to generate repeating future */
        def createFuture(): Future[Unit] = {
            runRepeatingTaskCommand(arg)).flatMap { _ =>
                scheduler.repeatDelay(name) match {
                    case Some(d) =>
                        Thread.sleep(d)
                        Future(createFuture())
                    case None =>
                        Future.successful(())
                }
            }
        }

        /* spin off repeating task */
        if (scheduler.isScheduled(name)) {
            Future.failure(new CommandException(s"task $name is already running"))
        } else {
            scheduler.schedule(name, delay)
            createFuture()
        }
  }
}

上面的代码将集成到一些读取用户输入并调用以下一些调用的REPL中:

implicit val scheduler: Scheduler = new SchedulerImpl

runCommand(OneTimeTaskCommand(someArg))

// Run backgrounded task to be repeated every second
runCommand(RepeatingTaskCommand("backgrounded-task", 1000L, someArg))

// Stop backgrounded task
runCommand(StopTaskCommand("backgrounded-task"))

0 个答案:

没有答案