简体   繁体   中英

amphp auto-load class not working as expected

I'm trying to use a custom class in a worker using amphp but it doesn't seem to be working. The below class is already auto-loaded using composer. Please help me out with this issue. My code is below:

Class (this implements Task as mentioned on their docs):

<?php

namespace Jobs;

require '/home/xxx/vendor/autoload.php';

use Amp\Parallel\Worker\Environment;
use Amp\Parallel\Worker\Task;

class GetMarketJob implements Task {
    /**
     * @var callable
     */
    private $function;
    /**
     * @var mixed[]
     */
    private $args;

    public function __construct($function, ...$args) {
        $this->function = $function;
        $this->args = $args;
    }

    /**
     * {@inheritdoc}
     */
    public function run(Environment $environment)
    {
        if ($this->function instanceof \__PHP_Incomplete_Class) {
            throw new \Error('When using a class instance as a callable, the class must be autoloadable');
        }

        if (\is_array($this->callable) && ($this->callable[0] ?? null) instanceof \__PHP_Incomplete_Class) {
            throw new \Error('When using a class instance method as a callable, the class must be autoloadable');
        }

        if (!\is_callable($this->function)) {
            $message = 'User-defined functions must be autoloadable (that is, defined in a file autoloaded by composer)';
            if (\is_string($this->function)) {
                $message .= \sprintf("; unable to load function '%s'", $this->function);
            }

            throw new \Error($message);
        }

        return ($this->function)(...$this->args);
    }

    public function testMe($url = NULL) {
        $test = file_get_contents($url);
        return $test;
    }    
}

File using amphp to assign worker using above class:

    <?php

require '/home/xxxx/vendor/autoload.php';

use Jobs\GetMarketJob;
// Example async producer using promisor

use Amp\Parallel\Worker;
use Amp\Promise;
use Amp\Loop;
use Amp\Parallel\Worker\DefaultPool;
use Amp\Parallel\Worker\Task;
use Amp\Parallel\Worker\Environment;
use Amp\Parallel\Worker\TaskFailureError;
use Amp\Parallel\Worker\DefaultWorkerFactory;

Amp\Loop::run(function () {
    $factory = new DefaultWorkerFactory();

    $worker = $factory->create();

    $result = yield $worker->enqueue(new GetMarketJob('testMe', ['https://www.syhtek.com']));
    
    print($result);

    $code = yield $worker->shutdown();
    \printf("Code: %d\n", $code);
});

running this script gives me the below output:

[26-May-2021 01:23:11 UTC] PHP Fatal error: Uncaught Amp\Parallel\Worker\TaskFailureError: Uncaught Error in worker with message "User-defined functions must be autoloadable (that is, defined in a file autoloaded by composer); unable to load function 'testMe'" and code "0"; use Amp\Parallel\Worker\TaskFailureError::getOriginalTrace() for the stack trace in the worker in /home/xxxx/vendor/amphp/parallel/lib/Worker/Internal/TaskFailure.php:60

Thank you so much for reading!

The issue here is that you're passing 'testMe' and then check if (!\is_callable($this->function)) { , while it should be if (,\method_exists($this, $this->function)) { .

And return ($this->function)(...$this->args); should be return ($this->{$this->function})(...$this->args); if you're trying to call that method. You might also call that method directly instead of giving it to the constructor.

If everything you do in the worker is an HTTP request, you should look into amphp/http-client instead of amphp/parallel , as non-blocking I/O is much more efficient than several chlid processes with blocking I/O.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM