SublimeText / sublime_lib

Utility library for frequently used functionality in Sublime Text and convenience functions or classes
https://sublimetext.github.io/sublime_lib
MIT License
52 stars 4 forks source link

Spawn a separate process using the system's Python to track when ST is closed and allow cleanups #128

Open FichteFoll opened 4 years ago

FichteFoll commented 4 years ago

This is something that ST just cannot do at the moment and thus leaves plugins mostly struggling to clean up their resources or whatever. Because it's something that can be reused easily and only needs a single guardian process, there should be a centralized solution and sublime_lib provides a good opportunity to do so.

In essence:

  1. Provide an interface that users can call with the path to an executable (script) that will be run once it is detected that ST has been shut down. Also pass provided arguments to the subprocess call.
  2. On the first of such call, spawn a subprocess using the system python that will monitor its parent existence and has a communication channel with the plugin so that more on_exit executables can be added.
  3. Once ST has been closed, run the specified scripts with the respective arguments in parallel.

Optional: Log errors or failed calls in some log file, probably in the cache.

I suppose using standard pipes for communication and declaring ST as having closed when the pipe is broken works, too.

Related: https://github.com/SublimeTextIssues/Core/issues/2950

FichteFoll commented 4 years ago

Since Windows doesn't ship Python by default, we may be able to get the same result with a PowerShell script. I can't really help with that, however.

evandrocoan commented 4 years ago

If it is not found installed, we could ship some Python :stuck_out_tongue: Python is good for your health :innocent:

Thom1729 commented 4 years ago

The good news is that Sublime already comes with a perfectly serviceable Python interpreter: plugin_host. The bad news is that a) this is the thing that we want to wait on, and it can't wait on itself, and b) it doesn't end via sys.exit() so we can't use atexit to register exit handlers.

What we can do, though, is:

1. Fork plugin_host.
2a. In the parent, os.wait() for the child. 2b. In the child:     1. Do normal daemonization stuff (close fds, chdir, whatever).     2. Fork.     3a. In the parent, os._exit(0).     3b. In the child:         1. Set an atexit handler to:             1. Sleep in a loop until the original plugin_host PID is gone.             2. Run cleanup code.         2. sys.exit(0).

FichteFoll commented 4 years ago

Reusing plugin_host is a neat idea because it means packages don't need to provide executables (and a .no-sublime-package), since we can run the cleanup code from within ST's environment. Unfortunately, again, this won't work on Windows.

Why do we need to os.wait() though? couldn't we just use the first child already?

Thom1729 commented 4 years ago

Unfortunately, again, this won't work on Windows.

Ugh. I forgot that Windows doesn't have fork. Is there a similar strategy that might work for Windows? The important thing about fork is that it allows you to continue execution in a Python interpreter that's already set up and ready to go, without worrying about how to initialize plugin_host or about multiple hosts interfering with each other. (It occurs to me that a hypothetical version of Sublime supporting a new Python runtime might be better behaved in this regard.)

Why do we need to os.wait() though? couldn't we just use the first child already?

I'm cribbing from the standard double-fork daemonization strategy. The purpose of the double-fork has to do with setsid(); I forget the details. Our implementation might vary.

neuged commented 4 years ago

Apparently this issue is also related: https://github.com/SublimeTextIssues/Core/issues/10 (duplicate to the above mentioned).

And though it is an old issue, it was added to their "next dev cycle" milestone recently!

FichteFoll commented 4 years ago

Oh, sneaky. I didn't notice that. Thanks for the heads-up.

FichteFoll commented 4 years ago

Since this has been added for the new environment in 4050+, I believe we don't need this anymore, though I haven't tested it yet.

deathaxe commented 4 years ago

Agree, I think the ability to do cleanups by on_exit event handlers is enough. The idea of starting arbitrary scripts upon or after application exit feels like a hack. The dependency of external script interpreters even makes it awkward and error prone.

Plugins should be able to do cleanups upon application startup etc. in case ST crashed and therefore didn't call on_exit.