Skip to content

Daemon App Domain #206

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

Merged
merged 17 commits into from
Mar 14, 2019
Merged

Daemon App Domain #206

merged 17 commits into from
Mar 14, 2019

Conversation

grouma
Copy link
Member

@grouma grouma commented Mar 13, 2019

  • Depend on SSE v 2.0.0 as it fixes an issue with multiple listeners on the connection stream
    • Note this requires me to recompile the client.js
  • Create DevWorkflow abstraction
    • This handles all things related to web development, e.g. launching chrome
  • Update serve and daemon command to make use of DevWorkflow
  • Create AppDomain for the daemon command
    • Note that this domain depends on the ServerManager
  • Move _WebdevClient out of DevHandler and into WebdevVmClient
    • Note this will eventually be used heavily in the AppDomain.
  • Update DevHandler so that we can easily create a DebugService
    • I might tweak this in the future
  • Make minor tweaks to the logging so that it is properly handled in the daemon command
  • Add corresponding tests for the new App Domain events

@grouma grouma requested a review from jakemac53 March 13, 2019 20:29
@grouma grouma changed the title App start Daemon App Domain Mar 13, 2019
}

Future<String> _restart(Map<String, dynamic> args) async {
throw UnimplementedError();
Copy link
Contributor

Choose a reason for hiding this comment

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

you could implement this as _callServiceExtension('hotRestart') now if you wanted in this PR (that is ultimately probably what it should be)

Copy link
Member Author

Choose a reason for hiding this comment

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

Gonna wait for a follow up PR as I'd like to add some tests.

webdev.stdin.add(utf8.encode('[{"method":"daemon.shutdown","id":0}]\n'));
// Try to shutdown webdev cleanly before killing it.
await webdev.exitCode.timeout(const Duration(seconds: 5), onTimeout: () {
webdev.kill();
Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm putting a timeout like this in the test seems like it will just hide actual issues. Presumably intellij etc won't be killing us like this.

Copy link
Member Author

Choose a reason for hiding this comment

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

I suppose we can can listen for kill signals and try to gracefully close in webdev. The issue I'm trying to solve is that Chrome doesn't properly shutdown if webdev is killed. I can rework some stuff to see if there is a better pattern.

Copy link
Member Author

Choose a reason for hiding this comment

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

No luck. I've experienced this in the past. If you kill the parent process of Chrome it will live on sometimes. This simply prevents random Chrome instances from staying open after doing a local test run. It should not have any impact on the tests.

Copy link
Contributor

Choose a reason for hiding this comment

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

Presumably intellij etc won't be killing us like this.

FWIW, in VS Code we do something similar to this:

https://github.com/Dart-Code/Dart-Code/blob/master/src/debug/flutter_debug_impl.ts#L176-L177
https://github.com/Dart-Code/Dart-Code/blob/master/src/debug/dart_debug_impl.ts#L420-L423

To avoid having processes hang around, we:

  • Send a message using the API to stop/detach
  • Wait a seconds
  • Call .kill() (which sends SIGTERM)
  • Wait two seconds
  • Call .kill(sigkill)

Calling SigKill is bad, because it won't let the process clean up any of its child processes, but sometimes sigterm either doesn't work quickly and we don't know if the process will terminate, so we have to gamble with a sigkill.

That said - I do also wonder if doing it here might mask issues (for example, if shutdown doesn't work at all, won't this just silently kill it after 5 seconds and it could go unnoticed?).

If you kill the parent process of Chrome it will live on sometimes.

I had a similar issue with flutter_tester (see flutter/flutter#20949 (comment)) and I was never able to find conclusive information on what the mechanism is for child processes terminating when their parent does (I couldn't find whether the child was supposed to notice the parent die and terminate, or whether the parent should terminate the child, or whether the OS should do it, etc.).

In Dart-Code, we now have "additionalPidsToTerminate" in some places, where we just collect up the PIDs we can and terminate them all.

Copy link
Contributor

Choose a reason for hiding this comment

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

I would like to continue to push back on this - it seems as if sending the shutdown signal is not actually causing the daemon to shut down which isn't correct behavior.

If we are having issues actually shutting down webdev due to some streams being open or something then we should add a hard exit when we get the shutdown command, so that IDE's don't experience the same issue as the tests (and file an issue to diagnose the root cause).

If we want the test to clean itself up better after failures, then we could leave a timeout like this in but also throw an exception so the test will still fail and not silently kill webdev and succeed.

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks for the details!

We used to do something similar in package:test. Dartium was especially hard to kill. You could kill the main process of Dartium and its child processes would be promoted. Really weird. We ended up going with a hack where we would explicitly call kill on each child process of Dartium before killing the main process.

Normally when you hit ctrl+c from WebDev the launched Chrome instance is also killed. However if you kill WebDev right after Chrome launches (as in these test cases) then for some reason Chrome isn't properly "attached" and lives on. All other child processes of WebDev are correctly cleaned up. I'm also extremely confident that the build daemon is properly shutdown as I spent weeks ensuring that was the case. We also have tests for it as well.

Finally, I'm confident that WebDev properly shutsdown with the daemon exit command as we have a test for this functionality in daemon_domain_test.dart. It does not exercise this exitWebDev code path.

@@ -19,10 +19,10 @@ class Daemon {
Daemon(
Stream<Map<String, dynamic>> commandStream,
this._sendCommand,
Future<ServeController> futureServeController,
Future<ServerManager> futureServerManagers,
Copy link
Contributor

Choose a reason for hiding this comment

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

futureServerManager

chrome.chromeConnection,
Future<DebugService> startDebugService(
ChromeConnection chromeConnection, String appUrl) async {
return await DebugService.start(
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: you don't need the await here

webdev.stdin.add(utf8.encode('[{"method":"daemon.shutdown","id":0}]\n'));
// Try to shutdown webdev cleanly before killing it.
await webdev.exitCode.timeout(const Duration(seconds: 5), onTimeout: () {
webdev.kill();
Copy link
Contributor

Choose a reason for hiding this comment

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

I would like to continue to push back on this - it seems as if sending the shutdown signal is not actually causing the daemon to shut down which isn't correct behavior.

If we are having issues actually shutting down webdev due to some streams being open or something then we should add a hard exit when we get the shutdown command, so that IDE's don't experience the same issue as the tests (and file an issue to diagnose the root cause).

If we want the test to clean itself up better after failures, then we could leave a timeout like this in but also throw an exception so the test will still fail and not silently kill webdev and succeed.

@grouma
Copy link
Member Author

grouma commented Mar 14, 2019

With regards to #206 (comment) see my discussion here #206 (comment).

We do have a test that the WebDev process is properly killed and it does not exercise the exitWebDev code path. That code path simply ensures instances of chrome are not left around after doing a local run.

@grouma grouma merged commit 71880b3 into master Mar 14, 2019
@grouma grouma deleted the app-start branch March 14, 2019 18:58
@grouma grouma mentioned this pull request Mar 15, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants