Skip to content

Commit fc201b3

Browse files
authored
Merge pull request #183 from laravel/feat/improve-serve-assets
Removes 500 public assets limitation and makes files uploads concurrent
2 parents 9e93d9e + 5340a42 commit fc201b3

File tree

3 files changed

+98
-35
lines changed

3 files changed

+98
-35
lines changed

src/Aws/AwsStorageProvider.php

+58-5
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@
55
use GuzzleHttp\Client;
66
use GuzzleHttp\Pool;
77
use GuzzleHttp\Psr7\Request;
8+
use Illuminate\Support\LazyCollection;
89
use Laravel\VaporCli\ConsoleVaporClient;
9-
use Laravel\VaporCli\Exceptions\CopyRequestFailedException;
10+
use Laravel\VaporCli\Exceptions\RequestFailedException;
1011
use Laravel\VaporCli\Helpers;
1112
use Symfony\Component\Console\Helper\ProgressBar;
1213

@@ -84,16 +85,68 @@ public function request($method, $url, array $headers = [])
8485
]));
8586
}
8687

88+
/**
89+
* Execute the given store requests.
90+
*
91+
* @param array $requests
92+
* @param string $assetPath
93+
* @param callable $callback
94+
* @return void
95+
*/
96+
public function executeStoreRequests($requests, $assetPath, $callback)
97+
{
98+
collect($requests)->chunk(10)->each(function ($chunkOfRequests) use ($assetPath, $callback) {
99+
$requests = LazyCollection::make($chunkOfRequests)->map(function ($request) use ($assetPath) {
100+
$file = $assetPath.'/'.$request['path'];
101+
$request['stream'] = fopen($file, 'r+');
102+
103+
return $request;
104+
});
105+
106+
$generator = function () use ($requests, $callback) {
107+
foreach ($requests as $request) {
108+
$callback($request);
109+
110+
yield new Request(
111+
'PUT',
112+
$request['url'],
113+
array_merge(
114+
$request['headers'],
115+
['Cache-Control' => 'public, max-age=31536000']
116+
),
117+
$request['stream']
118+
);
119+
}
120+
};
121+
122+
(new Pool(new Client(), $generator(), [
123+
'concurrency' => 10,
124+
'rejected' => function ($reason, $index) {
125+
throw new RequestFailedException($reason->getMessage(), $index);
126+
},
127+
]))
128+
->promise()
129+
->wait();
130+
131+
$requests->each(function ($request) {
132+
fclose($request['stream']);
133+
});
134+
});
135+
}
136+
87137
/**
88138
* Execute the given copy requests.
89139
*
90140
* @param array $requests
141+
* @param callable $callback
91142
* @return void
92143
*/
93-
public function executeCopyRequests($requests)
144+
public function executeCopyRequests($requests, $callback)
94145
{
95-
$requests = function () use ($requests) {
146+
$generator = function () use ($requests, $callback) {
96147
foreach ($requests as $request) {
148+
$callback($request);
149+
97150
yield new Request(
98151
'PUT',
99152
$request['url'],
@@ -105,10 +158,10 @@ public function executeCopyRequests($requests)
105158
}
106159
};
107160

108-
(new Pool(new Client(), $requests(), [
161+
(new Pool(new Client(), $generator(), [
109162
'concurrency' => 10,
110163
'rejected' => function ($reason, $index) {
111-
throw new CopyRequestFailedException($reason->getMessage(), $index);
164+
throw new RequestFailedException($reason->getMessage(), $index);
112165
},
113166
]))
114167
->promise()

src/Exceptions/CopyRequestFailedException.php renamed to src/Exceptions/RequestFailedException.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
use RuntimeException;
66

7-
class CopyRequestFailedException extends RuntimeException
7+
class RequestFailedException extends RuntimeException
88
{
99
/**
1010
* The file index.

src/ServeAssets.php

+39-29
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
namespace Laravel\VaporCli;
44

55
use Laravel\VaporCli\Aws\AwsStorageProvider;
6-
use Laravel\VaporCli\Exceptions\CopyRequestFailedException;
6+
use Laravel\VaporCli\Exceptions\RequestFailedException;
77

88
class ServeAssets
99
{
@@ -18,21 +18,28 @@ class ServeAssets
1818
public function __invoke(ConsoleVaporClient $vapor, array $artifact, $fresh)
1919
{
2020
$assetPath = Path::build().'/assets';
21-
22-
$requests = $this->getAuthorizedAssetRequests(
23-
$vapor,
24-
$artifact,
25-
$assetFiles = $this->getAssetFiles($assetPath),
26-
$fresh
27-
);
28-
29-
$this->executeStoreAssetRequests($requests['store'], $assetPath);
30-
$this->executeCopyAssetRequests($requests['copy'], $assetPath);
31-
32-
$vapor->recordArtifactAssets(
33-
$artifact['id'],
34-
$assetFiles
35-
);
21+
$assetFiles = $this->getAssetFiles($assetPath);
22+
23+
collect($assetFiles)
24+
->chunk(400)
25+
->map
26+
->all()
27+
->each(function ($chunkOfAssetFiles) use ($assetPath, $vapor, $artifact, $fresh) {
28+
$requests = $this->getAuthorizedAssetRequests(
29+
$vapor,
30+
$artifact,
31+
$chunkOfAssetFiles,
32+
$fresh
33+
);
34+
35+
$this->executeStoreAssetRequests($requests['store'], $assetPath);
36+
$this->executeCopyAssetRequests($requests['copy'], $assetPath);
37+
38+
$vapor->recordArtifactAssets(
39+
$artifact['id'],
40+
$chunkOfAssetFiles
41+
);
42+
});
3643
}
3744

3845
/**
@@ -46,14 +53,19 @@ protected function executeStoreAssetRequests($requests, $assetPath)
4653
{
4754
$storage = Helpers::app(AwsStorageProvider::class);
4855

49-
foreach ($requests as $request) {
50-
Helpers::step('<comment>Uploading Asset:</comment> '.$request['path'].' ('.Helpers::kilobytes($assetPath.'/'.$request['path']).')');
56+
if (! empty($requests)) {
57+
try {
58+
$storage->executeStoreRequests($requests, $assetPath, function ($request) use ($assetPath) {
59+
Helpers::step('<comment>Uploading Asset:</comment> '.$request['path'].' ('.Helpers::kilobytes($assetPath.'/'.$request['path']).')');
60+
});
61+
} catch (RequestFailedException $e) {
62+
$request = $requests[$e->getIndex()];
63+
64+
Helpers::line("<fg=red>Uploading:</> {$request['path']}");
65+
Helpers::write($e->getMessage());
5166

52-
$storage->store(
53-
$request['url'],
54-
array_merge($request['headers'], ['Cache-Control' => 'public, max-age=31536000']),
55-
$assetPath.'/'.$request['path']
56-
);
67+
exit(1);
68+
}
5769
}
5870
}
5971

@@ -68,14 +80,12 @@ protected function executeCopyAssetRequests($requests, $assetPath)
6880
{
6981
$storage = Helpers::app(AwsStorageProvider::class);
7082

71-
foreach ($requests as $request) {
72-
Helpers::step('<fg=magenta>Copying Unchanged Asset:</> '.$request['path'].' ('.Helpers::kilobytes($assetPath.'/'.$request['path']).')');
73-
}
74-
7583
if (! empty($requests)) {
7684
try {
77-
$storage->executeCopyRequests($requests);
78-
} catch (CopyRequestFailedException $e) {
85+
$storage->executeCopyRequests($requests, function ($request) use ($assetPath) {
86+
Helpers::step('<fg=magenta>Copying Unchanged Asset:</> '.$request['path'].' ('.Helpers::kilobytes($assetPath.'/'.$request['path']).')');
87+
});
88+
} catch (RequestFailedException $e) {
7989
$request = $requests[$e->getIndex()];
8090

8191
Helpers::line("<fg=red>Copying:</> {$request['path']}");

0 commit comments

Comments
 (0)