Scala Monix , how to kill running or scheduled Task - scala

Im using Monix for asynchronous task workflow.
How do we kill a running Task ?
Task{ println("sleep")
Thread.sleep(200)
println("effect") }
.doOnCancel(Task(println("canceled")))
.timeout(100.milli) // timeout will do cancel
.runOnComplete(println)
#> Failure(java.util.concurrent.TimeoutException: Task timed-out after 100 milliseconds of inactivity)
sleep
canceled
effect <--- what !? , task is running. Isn't it canceled !?
My current solution is ugly in my opinion(the flag checking hinders the code reusing):
var flag=true
Task{
println("sleep")
Thread.sleep(200)
if (flag)
println("effect")
}
.doOnCancel(Task{ flag=false; println("canceled") })
.timeout(100.milli) // timeout will do cancel
If it is impossible, how do we kill a scheduled while not-yet-ran Task ?
My failed attempt is :
Task{ println("sleep"); Thread.sleep(200) }
.map{ _ => println("effect") }
.doOnCancel(Task(println("canceled")))
.timeout(100.milli) // timeout will do cancel
.runOnComplete(println)
Sadly it still shows the effect after the cancel happened. I hope that the scheduled and not-yet-ran Task can be canceled (the .map(...) is another Task, right?)

If you don't use Thread.sleep (which messes with the internals of Monix), but Task.sleep, things are working just fine.
Task
.defer {
println("start")
Task.sleep(1000.millis)
}
.map(_ => println("effect"))
.timeout(10.millis)
.doOnCancel(Task(println("canceling")))
Now, the question is what's your actual use case, because I'm sure you used Thread.sleep just for illustration purposes.

I found one of solutions if it is chain of tasks:
Task{println("start");Thread.sleep(1000)}
.asyncBoundary
.map{_=> println("effect")}
.doOnCancel(Task(println("canceling")))
.timeout(10.milli)
.executeWithOptions(_.enableAutoCancelableRunLoops)
.runOnComplete(println)
reference: https://github.com/monix/monix/issues/226
But I hope there are easy way to interrupt task instead of using closure or split and chaining tasks.

Related

Basic Task scheduling in FreeRTOS

Ivé been playing with two tasks only to learn the basics of FreeRTOS but i have some confusing things happening I can not understand.
I have two Tasks with the same priority:
xTaskCreate( vTaskLED1, "LED1", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL );
xTaskCreate( vTaskLED2, "LED2", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL );
Then, in each task i just turn on the corresponding led in order to know thich task is running.
// Task 1 to be created.
void vTaskLED1(void *pvParameters)
{
for( ;; )
{
GPIO_PortToggle(BOARD_INITPINS_LED1_GPIO, BOARD_INITPINS_LED1_GPIO_PIN_MASK);
// Task code goes here.
}
}
// Task 2 to be created.
void vTaskLED2(void *pvParameters)
{
for( ;; )
{
GPIO_PortToggle(BOARD_INITPINS_LED2_GPIO, BOARD_INITPINS_LED2_GPIO_PIN_MASK);
// Task code goes here.
}
}
And as I understand, as I have configUSE_PREEMPTION On and configUSE_TIME_SLICING Off, at this point the only running task would be LED1 since I never blocked or suspended this task.
Then I tested adding a TaskYELD() at the end of task 1 (LED1), this resoulted in just task 2 running all time (because this is never blocked or suspended) after one run of task 1.
Ath this moment everything is ok, but when I started testing with vTaskDelay( 1000 / portTICK_PERIOD_MS ); in order to block task 1, I don't get why this task is running even if task 2 is never blocked or suspended.
I can't understand why at the first two cases Task 1 was always READY but never ran and why in the third case ir runs even if there is a second Task running that never gets blocked or suspended.

wondering why scalaz Task.runAsyncInterruptibly not interrupting as i would expect it to

I've been looking at this presentation https://github.com/indyscala/scalaz-task-intro/blob/master/presentation.md and was confused about one of the code snippets it presented using Task.runAsyncInterruptibly (slightly modified appears below):
import java.util.concurrent.atomic.AtomicBoolean
import scalaz.concurrent.Task
import scalaz.{-\/, \/-}
object Junk extends App {
val neverMind = new AtomicBoolean(false)
System.out.println(s"neverMind set to $neverMind on thread ${Thread.currentThread().getName}")
val t = Task {
System.out.println(s" in task run block on thread ${Thread.currentThread().getName}")
Thread.sleep(4000)
System.out.println(s" completed sleep of 40000 ms on thread ${Thread.currentThread().getName}")
}
Task.fork(t).
//t.
runAsyncInterruptibly({
case -\/(t) => t.printStackTrace()
case \/-(()) => println(s"Completed (right) branch of case on thread ${Thread.currentThread().getName}")
}, neverMind)
println("sleeping 1000, then set nevermind to true")
Thread.sleep(1000)
neverMind.set(true)
println("woke up. set cancel=true -- expect stack trace not 'Completed' message")
Thread.sleep(4000)
}
I am puzzled because I set the 'cancel' flag (neverMind.set(true)), but I don't see a stack trace. the code block within delay {...} eventually prints 'completed successfully'. This is so simple, I am sure I am making a dumb mistake.. not sure where though !
I have sought advice from some colleagues who pointed out that my original example did not use Task.fork() so i was doing everything on the same thread... doh! OK. i corrected that. and it still does not work.
Thanks in advance for any guidance you can provide.
I think the answer has to do with the trampolining inside scalaz's Task/Future, as it only checks cancel in between steps (see listenInterruptibly inside scalaz's Future.
If you change the Task to:
val t = Task.delay(System.out.println(s" in task run block on thread ${Thread.currentThread().getName}"))
.map(_ => Thread.sleep(4000))
.map(_ => System.out.println(s" completed sleep of 40000 ms on thread ${Thread.currentThread().getName}"))
you'll see it gets canceled before the "completed sleep" step. It still didn't seem to call the handler that prints the stack trace, though.

Akka scheduler stops on exception; is it expected?

We run this code:
scheduler.schedule(1 minute, 1 minute) { triggerOperations.tick() }
when starting our application, where scheduler is an Akka actorSystem.scheduler.
If tick() throws an exception, then it is never called again!
I checked the documentation, but cannot find any statement that this is expected. Mostly the description is "Schedules a function to be run repeatedly with an initial delay and a frequency", with no mention that if the function throws an excpetion the task will stop firing.
Our akka version is 2.3.2.
http://doc.akka.io/docs/akka/2.3.4/scala/scheduler.html
http://doc.akka.io/api/akka/2.0/akka/actor/Scheduler.html
Is this behavior expected? Is it documented anywhere?
When in doubt, go to source. The code is a bit terse, but this fragment:
override def run(): Unit = {
try {
runnable.run()
val driftNanos = clock() - getAndAdd(delay.toNanos)
if (self.get != null)
swap(schedule(executor, this, Duration.fromNanos(Math.max(delay.toNanos - driftNanos, 1))))
} catch {
case _: SchedulerException ⇒ // ignore failure to enqueue or terminated target actor
}
}
shows that if your runnable throws, scheduler does not reschedule the next execution (which happens inside swap as far as I understand).

Play framework 2.0 long running tasks

My app has a long running task (anywhere from 5 minutes to 2 hours) that I can start through an admin panel.
I need a good way to know whether the task is currently running or not, so I can display the status on the admin panel and to prevent the task from being started twice.
Currently my code looks like this (simplified):
object TaskMonitor extends Controller {
var isRunning = false
// Displays the task status on the admin panel
def status = Action {
Ok.chunked(running &> Comet(callback = "parent.running"))
}
// Check task status every 100 ms
lazy val running: Enumerator[String] = {
Enumerator.generateM {
Promise.timeout(Some(isRunning.toString), 100 milliseconds)
}
}
// start the task, but only if it's not already running
def startTask = Action {
if (!isRunning) {
isRunning = true
val f = scala.concurrent.Future { Task.start }
f onComplete {
case _ => isRunning = false
}
}
Ok
}
}
Obviously this is has all kinds of issues, mainly the fact that I have unsynchronized mutable state (isRunning variable) in my controller.
What would be the correct way to go about what I want to achieve ?
You're right, you have unsynchronized mutable state. Is it really a problem? I mean this is your admin right? How many concurrent 'startTask' are you gonna send?
The recommended way to handle this in Play! is to use an Akka actor - you don't need any extra dependency, Play! includes Akka already.
Create an actor to hold your isRunning value; in startTask you can send a message to the actor to start the task (the actor will check if the task is not already running). To send the current status of the task you can query the actor for the value of isRunning.
This will give you a protected mutable state. Your choice to decide if it's really worth the trouble.

Scala program exiting before the execution and completion of all Scala Actor messages being sent. How to stop this?

I am sending my Scala Actor its messages from a for loop. The scala actor is receiving the
messages and getting to the job of processing them. The actors are processing cpu and disk intensive tasks such as unzipping and storing files. I deduced that the Actor part is working fine by putting in a delay Thread.sleep(200) in my message passing code in the for loop.
for ( val e <- entries ) {
MyActor ! new MyJob(e)
Thread.sleep(100)
}
Now, my problem is that the program exits with a code 0 as soon as the for loop finishes execution. Thus preventing my Actors to finish there jobs. How do I get over this? This may be really a n00b question. Any help is highly appreciated!
Edit 1:
This solved my problem for now:
while(MyActor.getState != Actor.State.Terminated)
Thread.sleep(3000)
Is this the best I can do?
Assume you have one actor you're want to finish its work. To avoid sleep you can create a SyncVar and wait for it to be initialized in the main thread:
val sv = new SyncVar[Boolean]
// start the actor
actor {
// do something
sv.set(true)
}
sv.take
The main thread will wait until some value is assigned to sv, and then be woken up.
If there are multiple actors, then you can either have multiple SyncVars, or do something like this:
class Ref(var count: Int)
val numactors = 50
val cond = new Ref(numactors)
// start your actors
for (i <- 0 until 50) actor {
// do something
cond.synchronized {
cond.count -= 1
cond.notify()
}
}
cond.synchronized {
while (cond.count != 0) cond.wait
}