pact-foundation / pact-plugins

🏰 Architecture to support Plugins 🔌 with Pact 🔗
MIT License
19 stars 11 forks source link

(windows) - plugins do not exit cleanly, if invoked from batch/ps1 script #73

Closed YOU54F closed 1 week ago

YOU54F commented 3 weeks ago

xy problem.

Trying to get the pact-avro-plugin working on windows, with Std::Process::Command in rust.

It uses a batch file, which means we get a terminate batch file y/n prompt, and it fails to exit cleanly, leaving test to hang unless cancelled via task manager.

We can replace it with a powershell script, to avoid the batch file prompt, but there is no way to invoke the powershell script, with powershell directly in the current impl, as we try and run the plugin entrypoint, from the plugins current working directory.

https://github.com/pact-foundation/pact-plugins/blob/e335629d492d652fe26abc560e0a15650e9f03cc/drivers/rust/driver/src/plugin_manager.rs#L267

could we potentially

1) if we detect a *.ps1 script, invoke powershell -Command 1) If this does solve it, it may be worth me dropping a pr into the https://github.com/sbt/sbt-native-packager project for it to also emit ps1 files as well as its current bat files. 2) ifargs` are supplied, they are not able to be provided on a case by case basis (so only for windows). I anticipated I may need extra args, but only in windows.

This follows on from https://github.com/austek/pact-avro-plugin/issues/42

Where I now have the plugin starting and the tests passing, but the plugin is just failing to cleanly exit.

open to other ideas :)

YOU54F commented 3 weeks ago

Ok, on windows the child.id that gets returned is that of the cmd prompt itself, and when it is killed, it doesn't kill it's children, so the java executable is left running

Taskkill has an option /t

/t : Specifies to terminate all child processes along with the parent process, commonly known as a tree kill.

https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-xp/bb491009(v=technet.10)?redirectedfrom=MSDN

2024-08-21T17:06:31.631505Z DEBUG ThreadId(01) pact_plugin_driver::plugin_manager: Plugin avro started with PID 11596
2024-08-21T17:06:35.269248Z DEBUG ThreadId(07) pact_plugin_driver::child_process_windows: Plugin(avro, 11596, STDERR) || SLF4J(I): Connected with provider of type [ch.qos.logback.classic.spi.LogbackServiceProvider]
2024-08-21T17:09:54.891278Z DEBUG ThreadId(02) pact_plugin_driver::plugin_manager: Shutting down all plugins
2024-08-21T17:09:54.891318Z DEBUG ThreadId(02) pact_plugin_driver::plugin_manager: Shutting down plugin PactPlugin { manifest: PactPluginManifest { plugin_dir: "X:/pact-foundation/pact-avro-plugin/target/avro-1.0.0", plugin_interface_version: 1, name: "avro", version: "1.0.0", executable_type: "exec", minimum_required_version: None, entry_point: "bin/pact-avro-plugin", entry_points: {"windows": "bin/pact-avro-plugin.bat"}, args: None, dependencies: Some([PluginDependency { name: "jvm", version: Some("17+"), dependency_type: Plugin }]), plugin_config: {} }, child: ChildPluginProcess { child_pid: 11596, plugin_info: RunningPluginInfo { port: 57036, server_key: "77868228-6623-4f36-9017-dd9b62df0f80" } }, access_count: 1 }

Process table

Handles  NPM(K)    PM(K)      WS(K)     CPU(s)     Id  SI ProcessName
-------  ------    -----      -----     ------     --  -- -----------
      7       2     1748        108       0.00  11596   1 cmd
    619      58   210916     180696       9.34   6224   1 java
YOU54F commented 3 weeks ago

So looks like this is code that is executed on windows for process.kill

https://github.com/GuillaumeGomez/sysinfo/blob/176db2852c29f3fcf35f213bebaa2790a35be454/src/windows/process.rs#L326C1-L335C6


    pub(crate) fn kill_with(&self, signal: Signal) -> Option<bool> {
        crate::sys::system::convert_signal(signal)?;
        let mut kill = process::Command::new("taskkill.exe");
        kill.arg("/PID").arg(self.pid.to_string()).arg("/F");
        kill.creation_flags(CREATE_NO_WINDOW.0);
        match kill.output() {
            Ok(o) => Some(o.status.success()),
            Err(_) => Some(false),
        }
    }
YOU54F commented 3 weeks ago

Yeah this definitely seems to be case

PS X:\pact-foundation\pact-go> Get-Process | Where {$_.Name -eq "cmd"} 

Handles  NPM(K)    PM(K)      WS(K)     CPU(s)     Id  SI ProcessName
-------  ------    -----      -----     ------     --  -- -----------
     94       6     4988       8948       0.20   6564   1 cmd

PS X:\pact-foundation\pact-go> Get-Process | Where {$_.Name -eq "java"}

Handles  NPM(K)    PM(K)      WS(K)     CPU(s)     Id  SI ProcessName
-------  ------    -----      -----     ------     --  -- -----------
    559      53   227200     132896       3.80  13148   1 java

PS X:\pact-foundation\pact-go> taskkill /f /pid 6564                   
SUCCESS: The process with PID 6564 has been terminated.
PS X:\pact-foundation\pact-go> Get-Process | Where {$_.Name -eq "java"}

Handles  NPM(K)    PM(K)      WS(K)     CPU(s)     Id  SI ProcessName
-------  ------    -----      -----     ------     --  -- -----------
    559      53   227200     132896       3.86  13148   1 java

Using /t option, kills both processes

PS X:\pact-foundation\pact-go> Get-Process | Where {$_.Name -eq "cmd"}

Handles  NPM(K)    PM(K)      WS(K)     CPU(s)     Id  SI ProcessName
-------  ------    -----      -----     ------     --  -- -----------
     94       6     4988       8944       0.11  12880   1 cmd

PS X:\pact-foundation\pact-go> Get-Process | Where {$_.Name -eq "java"}

Handles  NPM(K)    PM(K)      WS(K)     CPU(s)     Id  SI ProcessName
-------  ------    -----      -----     ------     --  -- -----------
    562      53   227564     134184       3.95   5912   1 java

PS X:\pact-foundation\pact-go> taskkill /f /pid 12880 /t               
SUCCESS: The process with PID 5912 (child process of PID 12880) has been terminated.
SUCCESS: The process with PID 12880 (child process of PID 8896) has been terminated.