question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

The only RoleTask does not exit after completion

See original GitHub issue

Greetings!

I’ve got a Cats IO based application with only RoleTask bootstrapped. Distage version: 1.0.8 My RoleTask contains long, blocking piece of code - but it doesn’t blocks forever.

I thought, that after completion of role’s start() method the application must exit - but it doesn’t. Am I wrong, assuming this behaviour?

My role looks something like this:

class MyTaskRole(
    sender: MySender[IO],
    @Id("myTask-role-logger") logger: Logger[IO]
) extends RoleTask[IO] {

  override def start(
      roleParameters: RawEntrypointParams,
      freeArgs: Vector[String]
  ): IO[Unit] =
    for {
      _ <- logger.info("Running sending task")
      _ <- sender.sendBatchesUntilEmpty
      _ <- logger.info("Sending task complete!")
    } yield ()
}

object MyTaskRole extends RoleDescriptor {
  override def id: String = "myTaskRole"

  object Plugin extends PluginDef {
    include(
      new RoleModuleDef {
        makeRole[MyTaskRole]
      }
    )
  }
}

sender.sendBatchesUntilEmpty is a blocking call, performing a long, blocking task. After its completion I see “Sending task complete!” message among logs. Also, I observe that line:

I 2021-08-04T17:48:26.407 (RoleAppEntrypoint.scala:82) …AppEntrypoint.Impl.runRoles [31:ioapp-compute-0] phase=late No services to run, exiting…

But, as I have already mentioned, application does not exit.

Here is example of my launcher - maybe it helps somehow. I had not override anything here.

object Launcher extends LauncherCats[IO] {

  implicit val ec: ExecutionContextExecutor =
    ExecutionContext.fromExecutor(
      Executors.newFixedThreadPool(10)
    )

  implicit val contextShiftIO: ContextShift[IO] = IO.contextShift(ec)

  implicit val concurrentEffectIO: ConcurrentEffect[IO] = IO.ioConcurrentEffect

  implicit val timerIO: Timer[IO] = IO.timer(ec)

  override protected def pluginConfig: PluginConfig =
    PluginConfig.const(
      Seq(
        MyTaskRole.Plugin,
        DI
      )
    )

  object DI extends PluginDef {
    // a bunch of include(...) directives
  }
}

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:7 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
amricko0bcommented, Sep 6, 2021

Oh, now I understand. Thanks, for explanation. My investigation took me very deep in details, but the answer was much more simple 😄

By the way, #1585 - great idea, will wait for that feature, but for now I’ll try the second option with helper)

I suppose this issue can be closed now. Again, thanks for your answers and patience)

0reactions
neko-kaicommented, Sep 6, 2021

@amricko0b Thanks for the reproduction! The problem in this demo is caused by creating a global – and non-daemon, so it prevents the VM from closing – execution context which is then never closed.

Solution: https://github.com/amricko0b/distage-1557/pull/1 In detail, this causes the VM to stuck and is generally preventable by either making thread pools daemonic using a custom ThreadFactory:

import scala.util.chaining.scalaUtilChainingOps

Executors.newFixedThreadPool(16, new ThreadFactory {
  def newThread(r: Runnable): Thread = new Thread(r).tap(_.setDaemon(true))
})

Or by closing the ExecutionContext properly using its .shutdown() method. Distage provides a Lifecycle.fromExecutorService helper for that:

make[ExecutionContext].fromResource {
  Lifecycle
    .fromExecutorService(Executors.newFixedThreadPool(16))
    .map(ExecutionContext.fromExecutor(_))
}

Also I think this problem be avoided in the future with this change https://github.com/7mind/izumi/pull/1585 - we already supply default bindings for ExecutionContext, but only for ZIO right now, I fixed that oversight in the PR so you may use a default ExecutionContext @Id("cpu") without having to make a custom one.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Node script does not exit after all setTimeout finished
The problem is that at the end of the script the shell prompt does not exit, the process remains hanging and I need...
Read more >
Task-Oriented Leadership: Definition and Examples - Indeed
This article explains what task-oriented leadership is and gives examples of characteristics of task-oriented leaders.
Read more >
Troubleshoot Azure RBAC | Microsoft Learn
You are unable to assign a role in the Azure portal on Access ... The role assignment name is not unique, and it...
Read more >
ISE for device admin prescriptive deployment guide
Based on the scenario, your challenge is to create a policy that allows every administrator to do just their task and not anymore...
Read more >
Task definition parameters - Amazon Elastic Container Service
For Amazon ECS tasks that are hosted on Amazon EC2 Linux instances, the valid values are none , bridge , awsvpc , and...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found