Skip to content
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

Fix handling of interrupting OxApp #175

Merged
merged 1 commit into from
Jul 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 17 additions & 13 deletions core/src/main/scala/ox/OxApp.scala
Original file line number Diff line number Diff line change
Expand Up @@ -25,23 +25,27 @@ trait OxApp:
protected def settings: AppSettings = AppSettings.Default

final def main(args: Array[String]): Unit =
unsupervised {
val cancellableMainFork = forkCancellable(supervised(handleRun(args.toVector)))
try
unsupervised {
val cancellableMainFork = forkCancellable(supervised(handleRun(args.toVector)))

val interruptThread = new Thread(() => {
cancellableMainFork.cancel()
()
})
val interruptThread = new Thread(() => {
cancellableMainFork.cancel()
()
})

interruptThread.setName("ox-interrupt-hook")
interruptThread.setName("ox-interrupt-hook")

mountShutdownHook(interruptThread)
mountShutdownHook(interruptThread)

cancellableMainFork.joinEither() match
case Left(iex: InterruptedException) => exit(settings.gracefulShutdownExitCode)
case Left(fatalErr) => throw fatalErr
case Right(exitCode) => exit(exitCode)
}
cancellableMainFork.joinEither() match
case Left(_: InterruptedException) => exit(settings.gracefulShutdownExitCode)
case Left(fatalErr) => throw fatalErr
case Right(exitCode) => exit(exitCode)
}
catch
// if .joinEither is interrupted, the exception will be rethrown, won't be returned as a Left
case ie: InterruptedException => exit(settings.gracefulShutdownExitCode)

/** For testing - trapping System.exit is impossible due to SecurityManager removal so it's just overrideable in tests. */
private[ox] def exit(exitCode: ExitCode): Unit = System.exit(exitCode.code)
Expand Down
3 changes: 3 additions & 0 deletions core/src/main/scala/ox/fork.scala
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,9 @@ trait Fork[T]:
/** Blocks until the fork completes with a result. Only makes sense in for unsupervised forks, that is when the fork is started using
* [[forkUnsupervised]] or [[forkCancellable]]; otherwise a thrown exception causes the scope to end, and is re-thrown by the
* [[supervised]] block.
*
* @throws InterruptedException
* If the join is interrupted.
*/
def joinEither(): Either[Throwable, T] =
try Right(join())
Expand Down
Loading