Skip to content

Issues with Future ? #124

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
nrinaudo opened this issue Dec 31, 2018 · 6 comments
Closed

Issues with Future ? #124

nrinaudo opened this issue Dec 31, 2018 · 6 comments

Comments

@nrinaudo
Copy link

Given the two following blocks:

```scala mdoc
import scala.concurrent._
import scala.concurrent.duration._
import ExecutionContext.Implicits.global

def longRunning(): Int = {
  Thread.sleep(100)
  println("LONG")
  1
}

def immediate(): Int = {
  println("IMMEDIATE")
  2
}

def combine(): Future[Int] = for {
  i <- Future(longRunning())
  j <- Future(immediate())
} yield i + j

And

```scala mdoc
Await.result(combine(), 500.millis)

I would expect the Future to complete.

This is what happens in 1.0.0, but 1.1.0 spits out the following stack trace:

java.lang.NoClassDefFoundError: Could not initialize class repl.Session$App$[error] (run-main-6) java.lang.ExceptionInInitializerError

	at scala.runtime.java8.JFunction0$mcI$sp.apply(JFunction0$mcI$sp.java:12)
	at scala.concurrent.Future$.$anonfun$apply$1(Future.scala:654)
	at scala.util.Success.$anonfun$map$1(Try.scala:251)
	at scala.util.Success.map(Try.scala:209)
	at scala.concurrent.Future.$anonfun$map$1(Future.scala:288)
	at scala.concurrent.impl.Promise.liftedTree1$1(Promise.scala:29)
	at scala.concurrent.impl.Promise.$anonfun$transform$1(Promise.scala:29)
	at scala.concurrent.impl.CallbackRunnable.run(Promise.scala:60)
	at java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1402)
	at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
	at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
	at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
	at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
[error] java.lang.ExceptionInInitializerError
[error] 	at repl.Session$.app(future_in_comprehensions.md:3)
[error] 	at mdoc.internal.document.DocumentBuilder$$doc$.$anonfun$build$2(DocumentBuilder.scala:76)
[error] 	at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:12)
[error] 	at scala.util.DynamicVariable.withValue(DynamicVariable.scala:58)
[error] 	at scala.Console$.withErr(Console.scala:192)
[error] 	at mdoc.internal.document.DocumentBuilder$$doc$.$anonfun$build$1(DocumentBuilder.scala:76)
[error] 	at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:12)
[error] 	at scala.util.DynamicVariable.withValue(DynamicVariable.scala:58)
[error] 	at scala.Console$.withOut(Console.scala:163)
[error] 	at mdoc.internal.document.DocumentBuilder$$doc$.build(DocumentBuilder.scala:75)
[error] 	at mdoc.internal.markdown.MarkdownCompiler$.buildDocument(MarkdownCompiler.scala:50)
[error] 	at mdoc.internal.markdown.MdocPostProcessor.processScalaInputs(MdocPostProcessor.scala:80)
[error] 	at mdoc.internal.markdown.MdocPostProcessor.processDocument(MdocPostProcessor.scala:35)
[error] 	at com.vladsch.flexmark.internal.PostProcessorManager.postProcess(PostProcessorManager.java:71)
[error] 	at com.vladsch.flexmark.internal.PostProcessorManager.processDocument(PostProcessorManager.java:54)
[error] 	at com.vladsch.flexmark.parser.Parser.postProcess(Parser.java:389)
[error] 	at com.vladsch.flexmark.parser.Parser.parse(Parser.java:369)
[error] 	at mdoc.internal.markdown.Markdown$.toDocument(Markdown.scala:81)
[error] 	at mdoc.internal.markdown.Markdown$.toMarkdown(Markdown.scala:114)
[error] 	at mdoc.internal.cli.MainOps.handleMarkdown(MainOps.scala:63)
[error] 	at mdoc.internal.cli.MainOps.handleFile(MainOps.scala:90)
[error] 	at mdoc.internal.cli.MainOps.$anonfun$generateCompleteSite$1(MainOps.scala:129)
[error] 	at scala.collection.LinearSeqOptimized.foldLeft(LinearSeqOptimized.scala:122)
[error] 	at scala.collection.LinearSeqOptimized.foldLeft$(LinearSeqOptimized.scala:118)
[error] 	at scala.collection.immutable.List.foldLeft(List.scala:85)
[error] 	at mdoc.internal.cli.MainOps.generateCompleteSite(MainOps.scala:127)
[error] 	at mdoc.internal.cli.MainOps.run(MainOps.scala:148)
[error] 	at mdoc.internal.cli.MainOps$.process(MainOps.scala:230)
[error] 	at mdoc.Main$.process(Main.scala:26)
[error] 	at mdoc.Main$.process(Main.scala:21)
[error] 	at mdoc.Main$.main(Main.scala:16)
[error] 	at mdoc.Main.main(Main.scala)
[error] 	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[error] 	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
[error] 	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
[error] 	at java.lang.reflect.Method.invoke(Method.java:497)
[error] Caused by: java.util.concurrent.TimeoutException: Futures timed out after [500 milliseconds]
[error] 	at scala.concurrent.impl.Promise$DefaultPromise.ready(Promise.scala:255)
[error] 	at scala.concurrent.impl.Promise$DefaultPromise.result(Promise.scala:259)
[error] 	at scala.concurrent.Await$.$anonfun$result$1(package.scala:215)
[error] 	at scala.concurrent.BlockContext$DefaultBlockContext$.blockOn(BlockContext.scala:53)
[error] 	at scala.concurrent.Await$.result(package.scala:142)
[error] 	at repl.Session$App$.<init>(future_in_comprehensions.md:48)
[error] 	at repl.Session$App$.<clinit>(future_in_comprehensions.md)
[error] 	at repl.Session$.app(future_in_comprehensions.md:3)
[error] 	at mdoc.internal.document.DocumentBuilder$$doc$.$anonfun$build$2(DocumentBuilder.scala:76)
[error] 	at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:12)
[error] 	at scala.util.DynamicVariable.withValue(DynamicVariable.scala:58)
[error] 	at scala.Console$.withErr(Console.scala:192)
[error] 	at mdoc.internal.document.DocumentBuilder$$doc$.$anonfun$build$1(DocumentBuilder.scala:76)
[error] 	at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:12)
[error] 	at scala.util.DynamicVariable.withValue(DynamicVariable.scala:58)
[error] 	at scala.Console$.withOut(Console.scala:163)
[error] 	at mdoc.internal.document.DocumentBuilder$$doc$.build(DocumentBuilder.scala:75)
[error] 	at mdoc.internal.markdown.MarkdownCompiler$.buildDocument(MarkdownCompiler.scala:50)
[error] 	at mdoc.internal.markdown.MdocPostProcessor.processScalaInputs(MdocPostProcessor.scala:80)
[error] 	at mdoc.internal.markdown.MdocPostProcessor.processDocument(MdocPostProcessor.scala:35)
[error] 	at com.vladsch.flexmark.internal.PostProcessorManager.postProcess(PostProcessorManager.java:71)
[error] 	at com.vladsch.flexmark.internal.PostProcessorManager.processDocument(PostProcessorManager.java:54)
[error] 	at com.vladsch.flexmark.parser.Parser.postProcess(Parser.java:389)
[error] 	at com.vladsch.flexmark.parser.Parser.parse(Parser.java:369)
[error] 	at mdoc.internal.markdown.Markdown$.toDocument(Markdown.scala:81)
[error] 	at mdoc.internal.markdown.Markdown$.toMarkdown(Markdown.scala:114)
[error] 	at mdoc.internal.cli.MainOps.handleMarkdown(MainOps.scala:63)
[error] 	at mdoc.internal.cli.MainOps.handleFile(MainOps.scala:90)
[error] 	at mdoc.internal.cli.MainOps.$anonfun$generateCompleteSite$1(MainOps.scala:129)
[error] 	at scala.collection.LinearSeqOptimized.foldLeft(LinearSeqOptimized.scala:122)
[error] 	at scala.collection.LinearSeqOptimized.foldLeft$(LinearSeqOptimized.scala:118)
[error] 	at scala.collection.immutable.List.foldLeft(List.scala:85)
[error] 	at mdoc.internal.cli.MainOps.generateCompleteSite(MainOps.scala:127)
[error] 	at mdoc.internal.cli.MainOps.run(MainOps.scala:148)
[error] 	at mdoc.internal.cli.MainOps$.process(MainOps.scala:230)
[error] 	at mdoc.Main$.process(Main.scala:26)
[error] 	at mdoc.Main$.process(Main.scala:21)
[error] 	at mdoc.Main$.main(Main.scala:16)
[error] 	at mdoc.Main.main(Main.scala)
[error] 	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[error] 	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
[error] 	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Dele
@olafurpg
Copy link
Member

olafurpg commented Dec 31, 2018

Thanks for reporting! I'm able to reproduce. Interestingly, the same happens in the Scala REPL

$ scala
Welcome to Scala 2.12.7 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_192).
Type in expressions for evaluation. Or try :help.
scala> import scala.concurrent._, duration._, ExecutionContext.Implicits.global
import scala.concurrent._
import duration._
import ExecutionContext.Implicits.global

scala> Await.result(Future(1), 500.millis)
java.lang.NoClassDefFoundError: Could not initialize class $line10.$read$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$
	at scala.runtime.java8.JFunction0$mcI$sp.apply(JFunction0$mcI$sp.java:12)
	at scala.concurrent.Future$.$anonfun$apply$1(Future.scala:654)
	at scala.util.Success.$anonfun$map$1(Try.scala:251)
	at scala.util.Success.map(Try.scala:209)
	at scala.concurrent.Future.$anonfun$map$1(Future.scala:288)
	at scala.concurrent.impl.Promise.liftedTree1$1(Promise.scala:29)
	at scala.concurrent.impl.Promise.$anonfun$transform$1(Promise.scala:29)
	at scala.concurrent.impl.CallbackRunnable.run(Promise.scala:60)
	at java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1402)
	at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
	at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
	at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
	at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
java.util.concurrent.TimeoutException: Futures timed out after [500 milliseconds]
  at scala.concurrent.impl.Promise$DefaultPromise.ready(Promise.scala:255)
  at scala.concurrent.impl.Promise$DefaultPromise.result(Promise.scala:259)
  at scala.concurrent.Await$.$anonfun$result$1(package.scala:215)
  at scala.concurrent.BlockContext$DefaultBlockContext$.blockOn(BlockContext.scala:53)
  at scala.concurrent.Await$.result(package.scala:142)
  ... 28 elided

The same happens in the Ammonite REPL, but I can't reproduce with tut 🤔

@nrinaudo
Copy link
Author

It’s really odd that it happens at all, isn’t it? Is there something dodgy with the default execution context?

@olafurpg
Copy link
Member

Something is going on with val members of objects that access any execution context

scala> import scala.concurrent._, duration._
import scala.concurrent._
import duration._

scala> import java.util.concurrent.Executors
import java.util.concurrent.Executors

scala> implicit  val ec = ExecutionContext.fromExecutor(Executors.newCachedThreadPool())
ec: scala.concurrent.ExecutionContextExecutor = scala.concurrent.impl.ExecutionContextImpl@5f36c8e3

scala> Await.result(Future(1), 500.millis)
Exception in thread "pool-1-thread-1" java.lang.NoClassDefFoundError: Could not initialize class $line15.$read$$iw$$iw$$iw$$iw$$iw$$iw$
	at scala.runtime.java8.JFunction0$mcI$sp.apply(JFunction0$mcI$sp.java:12)
	at scala.concurrent.Future$.$anonfun$apply$1(Future.scala:654)
	at scala.util.Success.$anonfun$map$1(Try.scala:251)
	at scala.util.Success.map(Try.scala:209)
	at scala.concurrent.Future.$anonfun$map$1(Future.scala:288)
	at scala.concurrent.impl.Promise.liftedTree1$1(Promise.scala:29)
	at scala.concurrent.impl.Promise.$anonfun$transform$1(Promise.scala:29)
	at scala.concurrent.impl.CallbackRunnable.run(Promise.scala:60)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:748)
java.util.concurrent.TimeoutException: Futures timed out after [500 milliseconds]
  at scala.concurrent.impl.Promise$DefaultPromise.ready(Promise.scala:255)
  at scala.concurrent.impl.Promise$DefaultPromise.result(Promise.scala:259)
  at scala.concurrent.Await$.$anonfun$result$1(package.scala:215)
  at scala.concurrent.BlockContext$DefaultBlockContext$.blockOn(BlockContext.scala:53)
  at scala.concurrent.Await$.result(package.scala:142)
  ... 28 elided

It seems the execution context does not work from a static initializer..

@olafurpg
Copy link
Member

It works fine if you wrap the call in a def or lazy val first

scala> def x =Await.result(Future(1), 500.millis)
x: Int
scala> x
res2: Int = 1
scala> lazy val x= Await.result(Future(1), 500.millis)
x: Int = <lazy>
scala> x
res5: Int = 1

These workarounds don't work in mdoc however, I suspect because in the REPL those become separate objects.

Something fishy is going on, but I'm sure we can figure it out with more experimentation. I tried changing how we trigger the object constructor but that didn't help.

@olafurpg
Copy link
Member

I'm able to reproduce this error with tut now

cat in/in.md
```tut
import scala.concurrent._
import scala.concurrent.duration._
import ExecutionContext.Implicits.global
Await.result(Future(1), 500.millis)
```
  target git:(future)  coursier launch -r "https://dl.bintray.com/tpolecat/maven/" org.tpolecat:tut-core_2.12:0.6.10 -- \
  in out '.*\.md$' -classpath $(coursier fetch -p org.scala-lang:scala-library:2.12.8)
[tut] compiling: in/in.md
java.lang.NoClassDefFoundError: Could not initialize class $line7.$read$$iw$$iw$$iw$$iw$$iw$$iw$
	at scala.runtime.java8.JFunction0$mcI$sp.apply(JFunction0$mcI$sp.java:12)
	at scala.concurrent.Future$.$anonfun$apply$1(Future.scala:654)
	at scala.util.Success.$anonfun$map$1(Try.scala:251)
	at scala.util.Success.map(Try.scala:209)
  5 ```tut
	at scala.concurrent.Future.$anonfun$map$1(Future.scala:288)
	at scala.concurrent.impl.Promise.liftedTree1$1(Promise.scala:29)
	at scala.concurrent.impl.Promise.$anonfun$transform$1(Promise.scala:29)
	at scala.concurrent.impl.CallbackRunnable.run(Promise.scala:60)
	at java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1402)
	at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
	at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
	at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
	at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
[tut] *** Error reported at /Users/olafurpg/dev/mdoc/target/in/in.md:5
java.util.concurrent.TimeoutException: Futures timed out after [500 milliseconds]

The problem seems related to starting the future and awaiting on it in the same object constructor. For example,

The following program runs OK

object a {
  val x = Future(1)
}
object b {
  println(Await.result(a.x, Duration("500ms")))
}

while this program here doesn't

object a {
  val x = Await.result(Future(1), Duration("500ms")
}
object b {
  println(a.x)
}

olafurpg added a commit that referenced this issue Jan 1, 2019
Fixes #124

- enable -Ydelamdafy:inline by default to avoid future timeouts
- handle exceptions with null messages by delegating to cause if any, or
  falling back to the message "null".
- trim stacktrace of all exceptions, also causes.
- catch initialization exceptions in addition to `NonFatal`, since they
  happen when vals in mdoc code fences crash.
@olafurpg
Copy link
Member

olafurpg commented Jan 1, 2019

-Ydelambdafy:inline fixes the problem, opened #126 enabling it by default and improving error handling of exceptions so that multi-cause stack traces are more readable.

The timeout error is a Scala 2.12 bug scala/bug#9824

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants