-
-
Notifications
You must be signed in to change notification settings - Fork 8.6k
Description
Feature and motivation
Hey.
I'm using selenium with WebKitWebDriver (which feels a bit more lightweight, and is packaged for Debian, unlike e.g. geckodriver) for some automation tasks.
Not sure if this is a bug, but it doesn't just work to do e.g.:
driver = webdriver.WebKitGTK()(which errors out with Message: Unable to obtain driver for MiniBrowser; For documentation on this error, please visit: https://www.selenium.dev/documentation/webdriver/troubleshooting/errors/driver_location?) but I really have to do e.g.
service = webdriver.WebKitGTKService(executable_path="/usr/bin/WebKitWebDriver", port=8080)
driver = webdriver.WebKitGTK(service=service)which apparently starts WebKitWebDriver with -p 8080.
What I wanted to make sure is, that if my program ends/dies for whatever reason (including signals, well except SIGKILL[0]) then any of these subprocesses it starts are also killed.
I did something like:
import atexit
import signal
def cleanup():
# the cleanup
def handler(signalnum, frame):
sys.exit(128 + signalnum)
for s in (signal.SIGHUP, signal.SIGINT, signal.SIGQUIT, signal.SIGABRT, signal.SIGTERM):
signal.signal(s, handler)
atexit.register(cleanup)(the signal handler is needed because atexit would otherwise only work forSIGINT).
With WebKitWebDriver I get a whole bunch of child processes:
PID PPID PGID TPGID SESS COMMAND
283438 228886 283438 283438 228886 /usr/bin/python3 ./x.py
283439 283438 283439 283438 228886 /usr/bin/WebKitWebDriver --port=8080
283442 283439 283439 283438 228886 /usr/lib/x86_64-linux-gnu/webkit2gtk
283466 283442 283439 283438 228886 /usr/lib/x86_64-linux-gnu/webkit2g
283478 283442 283439 283438 228886 /usr/lib/x86_64-linux-gnu/webkit2g
283441 283438 283438 283438 228886 [true] <defunct>
Now my natural candidate for # the cleanup would have been to call service.stop(), but that only kills the parent process (PID 283439 above), the various webkit2gtk... remain forever. Ugly.
I've seen Service.send_remote_shutdown_command() but TBH, I don't quite understand what it should do or whether one should use it.
It does at least not stop and processes (and especially not the children).
The main requests of this issue would be:
- Auto-handle that more properly. I.e. if you start a process, do so in a new process group and kill that (may not work on Windows?).. or something like that?
Perhaps along the way, export the PGID for the user? - And/or allow to use an
executable_path=of e.g.Noneand don't start anything, but leave that task to the user (port=) would still be needed of course.
That's what I did now as a workaround, i.e. something like:
process = subprocess.Popen( ("/usr/bin/WebKitWebDriver", "--port=8080"), stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, process_group=0)which I do before starting with selenium… and my cleanup handler is something like:
process_group_id = process.pid
os.killpg(process_group_id, signal.SIGTERM)
process.terminate()
time.sleep(0.5)
os.killpg(process_group_id, signal.SIGKILL)
process.kill()
process.wait()
(with the process.terminate() and process.kill() being superfluous).
Selenium still tries to start it on it's own…
doesn't even notice that this fails, because the port is already bound to by my manually started driver, which I think should be a bug on it's own and then uses mine.
I can do:
service = webdriver.WebKitGTKService(executable_path="/bin/true", port=8080)But that's still ugly (this is btw. the zombie true process in he listing above.
Thanks,
Chris.
[0] Might be possible somehow at least on Linux with prctl() and PR_SET_PDEATHSIG, but haven't found out how to use that on a process group (guess it's not directly possible).
Usage example
see above