-
-
Save nickpoulos/07b335381205899e6da5ed5d609c6da8 to your computer and use it in GitHub Desktop.
[Concurrent Requests] Concurrent Pools Using Laravel #php #laravel
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// 1. Register the routes | |
Route::get('test/{lorem}', function ($lorem) { | |
sleep(3); | |
return response()->json([ | |
'message' => $lorem, | |
'token' => Str::random(), | |
]); | |
}); | |
// 2. Spin up 4 `php artisan serve` processes (they will get assigned from ports 8000..8003) | |
// 3. Register the macro | |
class PendingConcurrentPool | |
{ | |
private int $concurrency = 10; | |
private Closure $requestsBuilder; | |
public function __construct(Closure $requestsBuilder) | |
{ | |
$this->requestsBuilder = $requestsBuilder; | |
} | |
public function concurrency(int $amount): self | |
{ | |
$this->concurrency = $amount; | |
return $this; | |
} | |
public function wait(): Collection | |
{ | |
$responses = collect(); | |
$pool = new Pool(new Client(), call_user_func($this->requestsBuilder), [ | |
'concurrency' => $this->concurrency, | |
'fulfilled' => function (Response $response, $index) use ($responses) { | |
$responses[$index] = new \Illuminate\Http\Client\Response($response); | |
}, | |
'rejected' => function (RequestException $reason, $index) use ($responses) { | |
$responses[$index] = new \Illuminate\Http\Client\Response($reason->getResponse()); | |
}, | |
]); | |
$pool->promise()->wait(); | |
return $responses; | |
} | |
} | |
PendingRequest::macro('pool', function (Closure $requestsBuilder) { | |
return new PendingConcurrentPool($requestsBuilder); | |
}); | |
// 4. Paste this in your tests/Feature/ExampleTest.php | |
public function testSendsConcurrentRequests() | |
{ | |
$responses = Http::pool(function () { | |
return yield from [ | |
'req-1' => new Request('GET', 'http://localhost:8000/test/req-1'), | |
'req-2' => new Request('GET', 'http://localhost:8001/test/req-2'), | |
'req-3' => new Request('GET', 'http://localhost:8002/test/req-3'), | |
'req-4' => new Request('GET', 'http://localhost:8003/test/req-4'), | |
]; | |
})->concurrency(4)->wait(); | |
dump($responses->map->json()); | |
} | |
// 5. The output should be something like this: | |
/* | |
Illuminate\Support\Collection^ {#670 | |
#items: array:4 [ | |
"req-1" => array:2 [ | |
"message" => "req-1" | |
"token" => "hJXWAcsTzauf0pgM" | |
] | |
"req-2" => array:2 [ | |
"message" => "req-2" | |
"token" => "plkQsQEiHDhLF90i" | |
] | |
"req-3" => array:2 [ | |
"message" => "req-3" | |
"token" => "g1nPymiH4ao1BNSb" | |
] | |
"req-4" => array:2 [ | |
"message" => "req-4" | |
"token" => "VB9UXvu7ekbJ1dEC" | |
] | |
] | |
} | |
*/ | |
// Each request takes 3 seconds (see route, there is a sleep there), but since we | |
// are sending them all at once (we are sending 4 requests with a concurrency | |
// of 4), the total amount of time to send all 4 requests is 3 seconds. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment