11

The scaladoc for sys.addShutdownHook says shutdown hooks are NOT guaranteed to be run. Now this is entirely reasonable, as the JVM can hardly run shutdown hooks if you send the JVM a SIGKILL, or whatever the Windows equivalent is.

However shutdown hooks added with sys.addShutdownHook never seem to run, although those run with Runtime.getRuntime.addShutdownHook do.

A test -

scala> val t = new Thread { override def run = println("hi!") }
t: java.lang.Thread = Thread[Thread-4,5,main]

scala> Runtime.getRuntime.addShutdownHook(t)

scala> hi!
george@george-MacBook:~$ scala

(Skipped the startup message)

scala> val t = new Thread { override def run = println("hi!") }
t: java.lang.Thread = Thread[Thread-4,5,main]

scala> sys.addShutdownHook(t.run _)
res0: scala.sys.ShutdownHookThread = Thread[shutdownHook1,5,main]

scala> george@george-MacBook:~$

The documentation says "The hook is automatically registered: the returned value can be ignored" so it's not that we're supposed to add the thread returned by sys.addShutdownHook (and at any rate that causes "IllegalArgumentException: Hook previously registered" to be thrown).

Also, calling run on thread returned by addShutdownHook doesn't seem to do anything, which is suspicious.

George Simms
  • 3,930
  • 4
  • 21
  • 35
  • 1
    Are you using the Play framework? If so, you can use shutdown hooks. https://www.playframework.com/documentation/2.7.x/ScalaDependencyInjection#Stopping/cleaning-up – Sergiu Indrie Mar 19 '19 at 10:05

1 Answers1

25

The type signature of addShutdownHook is (source):

def addShutdownHook(body: => Unit): ShutdownHookThread

So, it is obvious why your code is not working. Expected is a call-by-name argument => Unit and you pass t.run _, which returns () => Unit - that is something entirely different.

Call-by-name parameters are not run until they are executed, passing t.run _ to it means that a function is created at the time when the call-by-name argument is called - you are not passing the function itself instead of the call-by-name argument.

Use

sys.addShutdownHook(t.run)

instead. Or don't use the thread at all and just pass the code that should be executed:

sys.addShutdownHook(println("hi"))
kiritsuku
  • 52,967
  • 18
  • 114
  • 136
  • What is the difference? If you compile this scala `class Foo { def bar(a: => Unit) = (); def baz(a: () => Unit) = (); }` the jvm bytecode of both methods seem to be the same and both seem to use Function0 – George Simms Nov 15 '14 at 10:33
  • See http://stackoverflow.com/questions/4543228/whats-the-difference-between-and-unit – kiritsuku Nov 15 '14 at 10:36
  • 2
    @GeorgeSimms You also get bitten by value discarding (see e.g. http://blog.bruchez.name/2012/10/implicit-conversion-to-unit-type-in.html). Because of it, your shutdown hook actually says "create a function `t.run _` and throw it away". – Alexey Romanov Nov 15 '14 at 17:29