phpyieldamphp

amphp: Promises in Loops


Sorry, guys, but I'm kinda getting crazy now spending Hours and just can't figure out what's wrong.

So I have a download class which needs to separate the download in chunks and then request each chunk as a separate request that's all fine where I'm kinda getting nowhere is my promises my yield never returns anything but also does not throw any error.

What it should do is go through the broken up chunk array then execute promises for the active chunks, wait for completion, then continue.

This is my test in the code base:

/**
 * Start Download
 * 
 * @return void
 */
private function download() {


    $app = $this->app;
    $_this = $this;

    $chunks = array();
    for ($i=0; $i < $this->chunkCount+20; $i++) { 

        $start = $i * $this->chunkSize;
        $end = ($i+1)*$this->chunkSize;

        if($i == $this->chunkCount-1) {
            $end = $this->size;
        }

        $chunks[] = (object) ['id' => ($i+1), 'start'=>$start , 'end'=>$end, $path = $this->path."/".$i];

    }

    $chunkedChunks = array_chunk($chunks, $this->connections);

    foreach($chunkedChunks as $key => $chunkedChunk) {

        $urls = [
            'https://secure.php.net',
            'https://amphp.org',
            'https://github.com',           
        ];

        $promises = [];
        foreach ($urls as $url) {
            $promises[$url] = \Amp\call(function() use ($url) {
                $deferred = new \Amp\Deferred();

                \Amp\Loop::delay(3 * 1000, function () use ($url, $deferred) {
                    $deferred->resolve($url);
                });

                return $deferred->promise();
            });
        }

        $responses = yield \Amp\Promise\all($promises);

        foreach ($responses as $url => $response) {
            \printf("Read %d bytes from %s\n", \strlen($response), $url);
        }

    
    }


}

I tried at least 20 variations, and it just won't work, the whole code runs in Loop::run

I know how to solve it differently by manually assigning tasks via Loop::repeat but that's not really the best way.

I would be grateful for help, perhaps I'm just loosing sight of what's going on or misunderstanding something.


Solution

  • Wrapping the foreach block in a separate asyncCall solved it in the end.