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

Timeout argument for run() #716

Open
martinhoyer opened this issue Jul 18, 2023 · 7 comments
Open

Timeout argument for run() #716

martinhoyer opened this issue Jul 18, 2023 · 7 comments
Labels
enhancement This issue/PR relates to a feature request.

Comments

@martinhoyer
Copy link
Contributor

Would it make sense to add an optional timeout argument to host.run?
In run_local it could be passed to p.communicate() and I imagine the other backends would have similar way to specify timeout.
Sorry if I'm missing something, I'm new to testinfra.

@philpep philpep added the enhancement This issue/PR relates to a feature request. label Aug 24, 2023
@gaellick
Copy link

@amaslenn
Copy link
Contributor

From BaseBackend:

    def run(self, command: str, *args: str, **kwargs: Any) -> CommandResult:
        raise NotImplementedError

So you can pass whatever parameter you want to host.run(), but the implementation depends on each backend.

@martinhoyer do you want all backends support timeout mandatory and change signature to

def run(self, command: str, timeout: int, *args: str, **kwargs: Any) -> CommandResult

?

@martinhoyer
Copy link
Contributor Author

@amaslenn Thanks for looking into it.
Looking at run_local(), it would have to be passed here:

        p = subprocess.Popen(
            cmd,
            shell=True,
            stdin=subprocess.PIPE,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
+           timeout=timeout
        )

The *args are being used to construct the actual command being run if I understand it correctly.

@amaslenn
Copy link
Contributor

@martinhoyer so you need only in BaseBackend::run_local(...)? This could look like this:

-    def run_local(self, command: str, *args: str) -> CommandResult:
+    def run_local(
+        self, command: str, *args: str, timeout: Optional[float] = None
+    ) -> CommandResult:
...
-        stdout, stderr = p.communicate()
+        stdout, stderr = p.communicate(timeout=timeout)

But will that do what you need? Backends like Ansible or SSH are using this function, but they won't pass timeout arg automatically, so changes in backends will also be needed. Overall interface might become unpredictable.

Yet timeout setting seems pretty useful.

@philpep what do you think, would such change make sense?

@martinhoyer
Copy link
Contributor Author

@amaslenn well, personally, I'm only using local for now, but I do realize that it would should be implemented in other backends, as mentioned in comment 0. If it's not as straightforward to implement there, then we can survive without it :)

SSH though should have a same "communicate" timeout argument at least afaik.

@amaslenn
Copy link
Contributor

SSH is slightly different, it uses -o ConnectTimeout=, not the timeout on Python level.

But anyway, this looks like a very useful feature. Yet maybe to keep the existing interface, BaseBackend should introduce a function like run_with_timeout. There are plenty of options here, let's wait for project owners to continue.

@martinhoyer
Copy link
Contributor Author

I see, it's running ssh commands directly. You can just pass it to run_local there as well then.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement This issue/PR relates to a feature request.
Projects
None yet
Development

No branches or pull requests

4 participants