High CPU usage while exiting sbt console strikes back

283 views
Skip to first unread message

eugene yokota

unread,
Apr 20, 2014, 11:48:59 PM4/20/14
to dispatc...@googlegroups.com
Hi,

The sbt console issue is back again.

Previously
- [CPU pins at 100% when quitting sbt console](https://groups.google.com/d/msg/dispatch-scala/CEZg9H32kX8/KRFaLQPFqDQJ)
- [reboot#58: High CPU usage in sbt interactive mode after exiting console](https://github.com/dispatch/reboot/issues/58)

console can exit fine on sbt 0.13.0, but on 0.13.1 and 0.13.2 the issue is back.

> console
[info] Starting scala interpreter...
[info] 
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
import dispatch._
import Defaults._
http: dispatch.Http = Http(com.ning.http.client.AsyncHttpClient@726223e6)
Welcome to Scala version 2.10.4 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_51).
Type in expressions to have them evaluated.
Type :help for more information.

scala> http(url("https://www.google.com/") > as.String)
res0: dispatch.Future[String] = scala.concurrent.impl.Promise$DefaultPromise@e56eabe

scala> res0()
res1: String = 
<!doctype html><html itemscope="" itemtype="http://schema.org/WebPage" lang="en"><head><meta content="Search the world's information, including webpages, images, videos and more. Google has many special features to help you find exactly what you're looking for." name="description"><meta content="noodp" name="robots"><meta content="/images/google_favicon_128.png" itemprop="image"><title>Google</title><script>(function(){
window.google={kEI:"15BUU8qsHpCWyAT8iYKABw",getEI:function(a){for(var b;a&&(!a.getAttribute||!(b=a.getAttribute("eid")));)a=a.parentNode;return b||google.kEI},https:function(){return"https:"==window.location.protocol},kEXPI:"17259,4000116,4007661,4007830,4008067,4008133,4008142,4009033,4009565,4009641,4010806,4010858,4010899,4011228,4011258,4011679,401195...
scala> http.shutdown

scala> sys.exit

// a long pause

Exception: sbt.TrapExitSecurityException thrown from the UncaughtExceptionHandler in thread "run-main-0"

// CPU going nuts

The TrapExitSecurityException is throw [here][1].
If I hit Ctrl-D instead of sys.exit, the screen freezes and nothing happens until I give up and hit Ctrl-C to get back to shell.

-eugene


Nathan

unread,
Apr 20, 2014, 11:50:05 PM4/20/14
to dispatc...@googlegroups.com
On 04/20/2014 11:48 PM, eugene yokota wrote:
> console can exit fine on sbt 0.13.0, but on 0.13.1 and 0.13.2 the issue
> is back.

Maybe we should file a bug with sbt? ;)

eugene yokota

unread,
Apr 21, 2014, 12:10:30 AM4/21/14
to dispatc...@googlegroups.com
That is definitely a possibility. Here is a comment from [a suspect commit][2], which happened after sbt 0.13.0.

 + /** Wait for all non-daemon threads for `app` to exit, for an exception to be thrown in the main thread,
 + * or for `System.exit` to be called in a thread started by `app`. */
 + private[this] def finish(app: App, log: Logger): Int =

After http.shutdown, would there still be some daemons running around?
If so it could explain the infinite-loop-like behavior as sbt turns MacBook Pro into a hot plate.

Nathan Hamblen

unread,
Apr 27, 2014, 12:34:33 PM4/27/14
to dispatc...@googlegroups.com
I did a little digging here and found the cause.

I don't use sys.exit() to exit the scala console and haven't tested what
happens there. I wouldn't know if high cpu usage in this scenario is a
regression or not.

The console exit method that Dispatch tries to support is ctrl+d or
:quit . This has regressed with sbt 0.13.1. The console fails to close,
as it does if any threads are still running.

The problem is here:
https://github.com/dispatch/reboot/blob/d7c5fb54aa86c7bebf73ff4921e5c03b1c268f59/core/src/main/scala/defaults.scala#L20-L23

Dispatch tries to determine if it's running inside an sbt console, and
if so, it uses a thread-pool configuration that calls the global
shutdown() when interrupted. We don't want this behavior in environments
outside sbt.

Dispatch knows it's in sbt if the current thread group's name is
"trap.exit". But in 0.13.1, this is no longer the case:

scala> Thread.currentThread.getThreadGroup.getName
res0: String = run-main-group-0

So Dispatch doesn't know it's in sbt and doesn't make those
accommodations. If you want to exit cleanly, you'll need to call
Http.shutdown() before :quit

Is there a better way I can know that we're in a Scala console inside
sbt, which will work for all sbt versions 0.12.x and 0.13.x ?

Nathan

On 04/21/2014 12:10 AM, eugene yokota wrote:
> That is definitely a possibility. Here is a comment from [a suspect
> commit][2], which happened after sbt 0.13.0.
>
> +/** Wait for all non-daemon threads for `app` to exit, for an
> exception to be thrown in the main thread,
> +* or for `System.exit` to be called in a thread started by `app`. */
> +private[this] def finish(app: App, log: Logger): Int =
>
> After http.shutdown, would there still be some daemons running around?
> If so it could explain the infinite-loop-like behavior as sbt turns
> MacBook Pro into a hot plate.
>
> -eugene
>
>
> [2]: https://github.com/sbt/sbt/commit/60426facba697b24d0d3d490f48525cdefc79daf
>
> On Sunday, April 20, 2014 11:50:05 PM UTC-4, n8han wrote:
>
> On 04/20/2014 11:48 PM, eugene yokota wrote:
> > console can exit fine on sbt 0.13.0, but on 0.13.1 and 0.13.2 the
> issue
> > is back.
>
> Maybe we should file a bug with sbt? ;)
>
> --
> You received this message because you are subscribed to the Google
> Groups "Dispatch" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to dispatch-scal...@googlegroups.com
> <mailto:dispatch-scal...@googlegroups.com>.
> For more options, visit https://groups.google.com/d/optout.

eugene yokota

unread,
Apr 27, 2014, 3:49:44 PM4/27/14
to dispatc...@googlegroups.com
On Sun, Apr 27, 2014 at 12:34 PM, Nathan Hamblen <nat...@technically.us> wrote:
The problem is here:
https://github.com/dispatch/reboot/blob/d7c5fb54aa86c7bebf73ff4921e5c03b1c268f59/core/src/main/scala/defaults.scala#L20-L23

Dispatch tries to determine if it's running inside an sbt console, and if so, it uses a thread-pool configuration that calls the global shutdown() when interrupted. We don't want this behavior in environments outside sbt.

Yea. I figured this was the reason sbt regressed.

 
Dispatch knows it's in sbt if the current thread group's name is "trap.exit". But in 0.13.1, this is no longer the case:

scala> Thread.currentThread.getThreadGroup.getName
res0: String = run-main-group-0

So Dispatch doesn't know it's in sbt and doesn't make those accommodations. If you want to exit cleanly, you'll need to call Http.shutdown() before :quit

Http.shutdown is not working for me. I call Http.shutdown and hit Ctrl+D, the console freezes without high CPU% (same behavior as before).

Is there a better way I can know that we're in a Scala console inside sbt, which will work for all sbt versions 0.12.x and 0.13.x ?


Before:
- val executionThread = new Thread(customThreadGroup, "run-main") { override def run() { executeMain } }
After: 
+ val executionThread = new Thread(app, "run-main")

So maybe I can bring the old name back or put "sbt" in the group name.
Also if there's a reliable way to shutting down the daemon thread, maybe sbt should add `exitCommands in console`?

-eugene

eugene yokota

unread,
Apr 27, 2014, 4:42:38 PM4/27/14
to dispatc...@googlegroups.com
On Sun, Apr 27, 2014 at 3:49 PM, eugene yokota <eed3...@gmail.com> wrote:
Dispatch knows it's in sbt if the current thread group's name is "trap.exit". But in 0.13.1, this is no longer the case:

scala> Thread.currentThread.getThreadGroup.getName
res0: String = run-main-group-0

So Dispatch doesn't know it's in sbt and doesn't make those accommodations. If you want to exit cleanly, you'll need to call Http.shutdown() before :quit

Http.shutdown is not working for me. I call Http.shutdown and hit Ctrl+D, the console freezes without high CPU% (same behavior as before).

scala> http.shutdown; Http.shutdown

and now I can Ctrl-D out.

-eugene

Nathan Hamblen

unread,
Apr 27, 2014, 9:44:50 PM4/27/14
to dispatc...@googlegroups.com
Yep, if you're using your own instance you'll need to shut it down
rather than the singleton. I should have been more specific. :)

My usual test case for this is just to run the block of code in the
intro tutorial, which uses the singleton.

http://dispatch.databinder.net/Dispatch.html

Nathan

Nathan Hamblen

unread,
Apr 27, 2014, 10:02:45 PM4/27/14
to dispatc...@googlegroups.com
On 04/27/2014 03:49 PM, eugene yokota wrote:
>
> On Sun, Apr 27, 2014 at 12:34 PM, Nathan Hamblen <nat...@technically.us
> <mailto:nat...@technically.us>> wrote:
>
> Is there a better way I can know that we're in a Scala console
> inside sbt, which will work for all sbt versions 0.12.x and 0.13.x ?
>
>
>
> https://github.com/sbt/sbt/commit/60426facba697b24d0d3d490f48525cdefc79daf#diff-afd4d7906c2a3bce7488d1bed1112e21L42
> Before:
> -val executionThread = new Thread(customThreadGroup, "run-main") {
> override def run() { executeMain } }
> After:
> +val executionThread = new Thread(app, "run-main")
>
> So maybe I can bring the old name back or put "sbt" in the group name.

Hm, don't worry about changing back the name, if nothing else I'll
update Dispatch to recognize either.

I feel like there's got to be some better way though, that didn't rely
on thread group names. Is there not a JVM property, or something else,
that would always and only be set when we're in this context?

> Also if there's a reliable way to shutting down the daemon thread, maybe
> sbt should add `exitCommands in console`?

If I understand correctly, then we would need to make sure everyone adds
that to their projects. The main motivation of this hack is so that
people don't have to RTFM or ask on the list, it just works the way they
expect.

I can't think of a way to do a hook from library code, without sbt
having scan the full classpath which I don't think is viable.

Nathan
Reply all
Reply to author
Forward
0 new messages