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

amphp/parallel + ssh2 #175

Open
hitriyvalenok opened this issue Apr 21, 2023 · 6 comments
Open

amphp/parallel + ssh2 #175

hitriyvalenok opened this issue Apr 21, 2023 · 6 comments
Labels

Comments

@hitriyvalenok
Copy link

hitriyvalenok commented Apr 21, 2023

Hello everyone! I like and very appreciate your work! Great library and docs!

I am trying to use ssh2 extension with parallel. Unfortunately, I am getting a mysterious issue. When I am calling a method in the object of my SSH class (for example, exec), the connection variable, initialized in the constructor, always resets to a "0" value instead of a resource. Full error looks like that:

Uncaught TypeError thrown in context with message "ssh2_exec(): Argument #1 ($session) must be of type resource, int given" and code "0" in SSH.php:18

What I am doing wrong? Thank you!

Main.php:

<?php
error_reporting( E_ALL & ~E_DEPRECATED );

use Amp\Parallel\Worker\ContextWorkerPool;
use Par\SSHExecTask;

require_once __DIR__ . '/vendor/autoload.php';

$pool = new ContextWorkerPool( 1 );
$ssh = new \Par\SSH( '127.0.0.1', 322, 'user', '123456' );
$task = $pool->submit( new SSHExecTask( $ssh ) );

$response = $task->await();
var_dump( $response );

src/SSH.php:

<?php
namespace Par;

class SSH
{
    private $connection;
    private $sftp;

    public function __construct( $host, $port, $user, $password )
    {
        $this->connection = ssh2_connect( $host, $port );
        ssh2_auth_password( $this->connection, $user, $password );
        $this->sftp = ssh2_sftp( $this->connection );
    }

    public function exec( $command )
    {
        $stdout = ssh2_exec( $this->connection, $command );
        $stderr = ssh2_fetch_stream( $stdout, SSH2_STREAM_STDERR );

        stream_set_blocking( $stdout, true );
        stream_set_blocking( $stderr, true );

        $stdoutContent = stream_get_contents( $stdout );
        $stderrContent = stream_get_contents( $stderr );

        if( $stderrContent ) {
            throw new \RuntimeException( $stderrContent );
        }

        fclose( $stdout );
        fclose( $stderr );

        return trim( $stdoutContent );
    }

    public function upload( $localFile, $remoteFile )
    {
        $stream = fopen( "ssh2.sftp://{$this->sftp}/$remoteFile", 'w' );
        return fwrite( $stream, file_get_contents( $localFile ) );
    }

    public function mkdir( $dirname, $mod = 0777, $recursive = false )
    {
        return ssh2_sftp_mkdir( $this->sftp, $dirname, $mod, $recursive );
    }
}

src/SSHExecTask.php:

<?php
namespace Par;

use Amp\Cancellation;
use Amp\Parallel\Worker\Task;
use Amp\Sync\Channel;

class SSHExecTask implements Task
{
    public function __construct(
        private readonly SSH $ssh
    ) {}

    public function run( Channel $channel, Cancellation $cancellation ): bool
    {
        return $this->ssh->exec( 'echo 123' );
    }
}

composer.json:

{
    "require": {
        "amphp/parallel": "^2.1",
        "ext-ssh2": "*"
    },
    "autoload": {
        "psr-4": {
            "Par\\": "src"
        }
    }
}
@hitriyvalenok
Copy link
Author

hitriyvalenok commented Apr 21, 2023

I've built a project you could deploy. You need PHP 8.0<= and ext-ssh2.

project.zip

@hitriyvalenok hitriyvalenok changed the title amp/parallel + ssh2 amphp/parallel + ssh2 Apr 21, 2023
@kelunik
Copy link
Member

kelunik commented Apr 21, 2023

You can't share objects over multiple parallel contexts. Objects are serialized and unserialized in the other context, so your connection will be lost during serialization.

@hitriyvalenok
Copy link
Author

You can't share objects over multiple parallel contexts. Objects are serialized and unserialized in the other context, so your connection will be lost during serialization.

Thanks! I'm starting to understand...

Could you please say why when a thread working my terminal sees nothing sent by echo/printf? I'm using logs to fix the issue, but it isn't very comfortable :(

@kelunik
Copy link
Member

kelunik commented Apr 21, 2023

These parallel contexts are child processes with their own standard input and output streams. I think we do have some automatic forwarding to the parent streams, but I'm not too sure on that.

@hitriyvalenok
Copy link
Author

hitriyvalenok commented Apr 21, 2023

You can't share objects over multiple parallel contexts. Objects are serialized and unserialized in the other context, so your connection will be lost during serialization.

I feel myself a stupid puppy :( Generally, I have two cute objects I'd like to send in the thread to use in. You know, it's about good practice. But I don't understand how it will be going in the context of parallel? What I can do with that? Do there any other parallel-like tools where I can do manage it better?

@kelunik
Copy link
Member

kelunik commented Apr 21, 2023

No, you'll have this problem with any PHP library that does similar things. You can pass the connection details to the child context instead of the connection itself and establish a new connection in every child.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Development

No branches or pull requests

2 participants