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

Redesign file watching and add client listeners #345

Merged
merged 12 commits into from
Mar 14, 2018
Merged

Conversation

jvican
Copy link
Contributor

@jvican jvican commented Mar 14, 2018

Nailgun has this great concept of client listeners: closures that are called
whenever the nailgun server thinks that the client has disconnected. These
closures receive the kind of event that the nailgun server got, and executes
some logic.

This concept allows bloop to register callbacks that are run to clean
resources. Cleaning resources is paramount to keep the right behaviour of
long-running tasks like file watching and bsp servers.

This PR does three things:

  1. Exposes the client listeners to the state, in a new abstraction called ClientPool.
  2. It uses client listeners to cancel tasks, whenever the tasks accept cancellation.
  3. Redesigns file watching in a Monix idiomatic style, with observables and
    consumers that help us reason about file watching events more reasonably.

Fixes #257 which was caused
because the cancellation of tasks for file watching did not work correctly
when CTRL-C was used.

It is important that we propagate these variables from the use site even
if the state is cached because they may be different for different
clients. The common options are also crucial (because we want to enable
future modifications of `System.in`, `System.out`, etc).
This folder is meant to be used to test bloop binaries in development.
The previous file watching logic was a monstruosity because:

1. It relied on `Await.result` to get the state for every of the actions
   run on file events.
2. It was difficult to reason about.
3. It was not possible to cancel it.

This new implementation uses the nifty `Observer` and `Observable`
interfaces to implement file watching in a reliable way, closing the
watcher when the implementation is cancelled or whenever an exception
happens in the watcher.

This issue fixes #257, which
was caused because file watchers of previous clients (connections) were
still running in the background and acting on events.
The previous one didn't work because `Observable` returns a list of
tasks, and that task cannot be processed and flattened until the stream
of file events has finished (never). This is bad, it means we cannot
fold left values produced by observables and then pass them in to
functions that return `Task`s.

For that, I've discovered you need `Consumer`, and there is one awesome
consumer that does exactly what we want: the one created with
`Consumer.foldLeftAsync`.
Fixes #257 which was caused
because the cancellation of tasks for file watching did not work
correctly when `CTRL-C` was used.
@jvican jvican added bug A defect or misbehaviour. nailgun task / watch labels Mar 14, 2018
Copy link
Collaborator

@Duhemm Duhemm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks awesome!

How hard would it be to make a NailgunTest for that?

import java.util.concurrent.atomic.AtomicInteger

import scala.Console.{CYAN, GREEN, RED, RESET, YELLOW}

import bloop.io.AbsolutePath
import com.martiansoftware.nailgun.NGCommunicator
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused import?

case object SocketError extends CloseEvent
case object SocketTimeout extends CloseEvent
case object SessionShutdown extends CloseEvent
case object InternalError extends CloseEvent
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not using NGClientDisconnectReason directly?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because I want not to depend on nailgun data structures as much as possible. Who knows what we'll use in the future. It didn't take a long time to do this, but in my opinion it's worth it 😄

pool.addListener {
case e: CloseEvent =>
if (!handle.isCompleted) {
System.out.println(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So that's writing to stdout of the server? Isn't that what ngout is for?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, but in this case the stdout that we see here is already ngout! I'll change it though, for clarity 😄

@jvican
Copy link
Contributor Author

jvican commented Mar 14, 2018

@Duhemm It was hard, but got it working. Now our logger also contains information about the server (which will be quite handy in the future!).

Copy link
Collaborator

@Duhemm Duhemm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

run(mainTest(args))
}

private[bloop] def mainTest(args: Array[String]): NGServer = {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure that's the best name? getServer? instantiateServer?


// We check here the logs because until 'exit' the server doesn't flush everything
val serverInfos = rlogger.getMessages().filter(_._1 == "server-info").map(_._2)
val cancellingTasks = serverInfos.filter(_.contains("Cancelling tasks..."))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

serverInfos.count(_.contains("Cancelling tasks...")) ?

@jvican
Copy link
Contributor Author

jvican commented Mar 14, 2018

Done! Please check your feedback is properly addressed 😄

@Duhemm
Copy link
Collaborator

Duhemm commented Mar 14, 2018

Great! Please merge when it's green 😄

@Duhemm Duhemm merged commit 072b2fe into master Mar 14, 2018
@jvican jvican deleted the topic/cancel-gracefully branch September 28, 2018 18:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug A defect or misbehaviour. nailgun task / watch
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants