Do DBIOActions composed in for comprehensions always run sequentially? - slick

I know that Futures in Scala, when grouped in for comprehensions, run sequentially unless they are declared outside of the for comprehension (as this article explains). Do DBIOActions work the same way? e.g. in the following query, is query1 guaranteed to execute before query2?
db.run {
for {
result1 <- query1.result
result2 <- query2.result
} yield (result1, result2)
}

Yes! query1 is guaranteed to run before query2. Remember that the for comprehension is equivalent to:
query1.reult.flatMap(result1 => query2.result.map(result2 => (result1, result2))
and the docs for flatMap on DBIOAction states that "Use the result produced by the successful execution of this action to compute and then run the next action in sequence."
http://slick.lightbend.com/doc/3.2.0/api/index.html#slick.dbio.DBIOAction#flatMap

Related

Scala - Executing every element until they all have finished

I cannot figure out why my function invokeAll does not give out the correct output/work properly. Any solutions? (No futures or parallel collections allowed and the return type needs to be Seq[Int])
def invokeAll(work: Seq[() => Int]): Seq[Int] = {
//this is what we should return as an output "return res.toSeq"
//res cannot be changed!
val res = new Array[Int](work.length)
var list = mutable.Set[Int]()
var n = res.size
val procedure = (0 until n).map(work =>
new Runnable {
def run {
//add the finished element/Int to list
list += work
}
}
)
val threads = procedure.map(new Thread(_))
threads.foreach(x => x.start())
threads.foreach (x => (x.join()))
res ++ list
//this should be the final output ("return res.toSeq")
return res.toSeq
}
OMG, I know a java programmer, when I see one :)
Don't do this, it's not java!
val results: Future[Seq[Int]] = Future.traverse(work)
This is how you do it in scala.
This gives you a Future with the results of all executions, that will be satisfied when all work is finished. You can use .map, .flatMap etc. to access and transform those results. For example
val sumOfAll: Future[Int] = results.map(_.sum)
Or (in the worst case, when you want to just give the result back to imperative code), you could block and wait on the future to get ahold of the actual result (don't do this unless you are absolutely desperate): Await.result(results, 1 year)
If you want the results as array, results.map(_.toArray) will do that ... but you really should not: arrays aren't really a good choice for the vast majority of use cases in scala. Just stick with Seq.
The main problem in your code is that you are using fixed size array and trying to add some elements using ++ (concatenate) operator: res ++ list. It produces new Seq but you don't store it in some val.
You could remove last line return res.toSeq and see that res ++ lest will be return value. It will be your work.length array of zeros res with some list sequence at the end. Try read more about scala collections most of them immutable and there is a good practice to use immutable data structures. In scala Arrays doesn't accumulate values using ++ operator in left operand. Array's in scala are fixed size.

How to concurrently create Future from Try?

The scala Future has a fromTry method which
Creates an already completed Future with the specified result or
exception.
The problem is that the newly created Future is already completed. Is it possible to have the evaluation of the Try done concurrently?
As an example, given a function that returns a Try:
def foo() : Try[Int] = {
Thread sleep 1000
Success(43)
}
How can the evaluation of foo be done concurrently?
A cursory approach would be to simply wrap a Future around the function:
val f : Future[Try[Int]] = Future { foo() }
But the desired return type would be a Future[Int]
val f : Future[Int] = ???
Effectively, how can the Try be flattened within a Future similar to the fromTry method?
There is a similar question, however the question & answer wait for the evaluation of the Try before constructing the completed Future.
Least ceremony is probably:
Future.unit.transform(_ => foo())
Special mention goes to #Dima for the suggestion of Future(foo().get) which is a bit shorter—but might be slightly less readable.
Based on the comments,
Scala >= 2.13:
val f : Future[Int] = Future.delegate(Future.fromTry(foo()))
Scala < 2.13:
val f : Future[Int] = Future(foo()).flatMap(Future.fromTry)

Groovy closures - not understandable call order

I try to build a small DSL, but I don't understand the following order of execution.
The DSL has a statement as summarize tests of 'me'
my Groovy script for interpretation is:
def tests = {
[of: { who ->
println "IN CLOSURE"
"HALLO" // dummy value for testing
}]
}
def summarize(Closure c) {
println "SUMMARIZE - CALL CLOSURE"
def f = c()
println "SUMMARIZE - CALL CLOSURE"
println "RESULT $f"
f
}
and my caller script has
def g = summarize tests of 'me'
println g
The output is
SUMMARIZE - CALL CLOSURE
SUMMARIZE - CALL CLOSURE
RESULT [of:com.github.groovyclient.TestRailClient$_closure1$_closure13#470f1802]
IN CLOSURE
HALLO
I actually want to have the result of the tests closure already in the summarize method, but it seems that there the inner closure has not been called yet - what magic is happening after that so that the script does have the correct result ?
Can someone explain me, why the order of execution ? And how can I retrieve HALLO already in the summarize method ?
Thanks for any help
In your example, test is a closure which returns a map.
If you call test() you'll get [of: {...}]
It's what you see in your console, when you print f.
For groovy
summarize tests of 'me'
is equivalent to
summarize(tests).of('me')
yours summarize(tests) execute tests(), which returns the map [of:{..}]. After that, you're executing map.of which return the close, and then you are calling this closure with the parameters me.
There are differents options to obtain what you want, but it depends on the full "dsl" you want to implement, not just this special usecase. The easiest way I think with only this sentence, is returning an intermediate object, which is triggered when you call `of':
def summarize(t) {
return [
of: { who ->
def f = t().of(who)
println f
}
]
}

Means for performing background operations in Scala

I'd like to do some time consuming task in background. So I need to start computation in a different thread, be able to check if it is completed (maybe failed) and be able to abort the computation when it becomes unnecessary. After computation is ended it should call synchronized callback function to store computed value.
It may be programmed as some wrapper over the Thread class. But I suppose that this basic functionality is implemented in some scala library already. I've tried to search but find only Akka that is too much for my simple task. scala.concurrent.ExecutionContext has useful execute method but it return no object to check status of the computation and abort it on demand.
What library contains already described functionality?
I've checked scala.concurrent.Future. It lacks ability to abort computation, that is crucial. I use following strategy: compute some consuming function in background and provide reasonable default. If arguments to the function is changed, I drop the original computation and start new. I could not imagine how to rewrite this strategy in terms of Future.flatMap.
I'll give a demonstration of how use futures with Twitter's implementation, since you asked for cancellation:
import com.twitter.util.{ Await, Future, FuturePool }
def computeFast(i: Int) = { Thread.sleep(1000); i + 1 }
def computeSlow(i: Int) = { Thread.sleep(1000000); i + 1 }
val fastComputation = FuturePool.unboundedPool(computeFast(1))
val slowComputation = FuturePool.unboundedPool(computeSlow(1))
Now you can poll for a result:
scala> fastComputation.poll
res0: Option[com.twitter.util.Try[Int]] = Some(Return(2))
scala> slowComputation.poll
res1: Option[com.twitter.util.Try[Int]] = None
Or set callbacks:
fastComputation.onSuccess(println)
slowComputation.onFailure(println)
Most of the time it's better to use map and flatMap to describe how to compose computations, though.
Cancellation is a little more complicated (this is just a demo—you'll want to provide your own cancellation logic):
import com.twitter.util.Promise
def cancellableComputation(i: Int): Future[Int] = {
val p = Promise[Int]
p.setInterruptHandler {
case t =>
println("Cancelling the computation")
p.setException(t)
}
FuturePool.unboundedPool(computeSlow(i)).onSuccess(p.setValue)
p
}
And then:
scala> val myFuture = cancellableComputation(10)
myFuture: com.twitter.util.Future[Int] = Promise#129588027(state=Interruptible(List(),<function1>))
scala> myFuture.poll
res4: Option[com.twitter.util.Try[Int]] = None
scala> myFuture.raise(new Exception("Stop this thing"))
Cancelling the computation
scala> myFuture.poll
res6: Option[com.twitter.util.Try[Int]] = Some(Throw(java.lang.Exception: Stop this thing))
You could probably do something similar with the standard library's futures.

How to use Q.all with delay?

I have a bunch of functions in an array allFunctions. I want them to be executed one after the other with delay between them. The closest I can think of is:
result = Q();
allFunctions.forEach(function(fn) {
result = result.then(fn).delay(1000);
})
Is this possible to do with the Q.all syntax?
Thank you in advance :)
Not in a meaningful way, a promise is an already started operation and Q.all waits for all actions to finish together.
What you currently have is the common way to do this, and it's very similar to the synchronous version (a for loop with sleep).
You can shorten it a bit with Array.prototype.reduce though:
var result = allFunctions.reduce(function(prev,fn){
return prev.then(fn).delay(1000);
},Q());
You can nest between your functions a Q().delay( 1000 )
This means that you would have to map your function array to:
function delay(){ return Q.delay(1000); }
var functions = [ f1, delay, f2, delay, f3 ];
Q.all will not run your functions sequentially, what you are doing with prev.then is an interesting hack, but you can also run it the way Q suggests it (more info here https://github.com/kriskowal/q#sequences):
var results = functions.reduce(Q.when, Q(initialVal));
Having the delays intercallated in your function array will also provide more control over the delays (if you eventually want different time delays)

Resources