大家好我只是有一个关于最佳实践的快速问题,也许还有一些关于排队和图像处理的帮助。
我目前在一个网站上工作,允许用户一次上传超过10个文件,根据我的经验,我只有真正处理单个上传或2-3个最大,这个网站允许用户上传尽可能多的喜欢然后执行图像处理以创建不同大小的每个图像的3个版本。
我的思考过程以及我如何实现这一点如下。
用户上传表单并选择多个文件,这些文件在完成表单自动提交后全部上传,上传的文件直接上传到S3中的临时文件夹,这是因为实时环境中有多个服务器在他们面前有一个负载均衡器所以我担心如果我把它们全部上传到服务器然后如果我解雇了一个队列它可能会去不正确的服务器而不是找到文件,如果有一个很好的做法会很好此
当提交表单时,它会向iron.io上的队列发送一个通知,其中包含表单提交中的数据,该数据基本上调用服务器并开始处理图像,代码如下所示
public function fire($job, $data)
{
set_time_limit(0);
try {
if(is_array($data)){
foreach ($data['file'] as $x => $file){ //loop through each file uploaded and now save them
if ($this->images->doesMediaExistInTemporaryFolder($file)){
if ($new_file = $this->images->getMediaFromTemporaryS3Folder($file)){
file_put_contents (app_path() . '/storage/bulk-upload/' . $file, (string) $new_file['Body']);
$record_date = false;
if ($data['date'][$x] != 'no-date'){
if ($new_file['ContentType'] == 'image/jpeg') {
$exif_data = @exif_read_data(app_path() . '/storage/bulk-upload/' . $file, 'FILE');
}
if (!empty($exif_data) && @array_key_exists('DateTime', $exif_data)){
$record_date = $exif_data['DateTime'];
} else {
$record_date = $data['date'][$x];
}
}
$created_file = new \Symfony\Component\HttpFoundation\File\UploadedFile(app_path() . '/storage/bulk-upload/' . $file, $file, $new_file['ContentType'] );
$input = array('vehicle_objectId' => $data['vehicle_objectId'], 'type' => $data['type'], 'privacy' => $data['privacy'], 'date' => $record_date);
if (file_exists(app_path() . '/storage/bulk-upload/' . $file)){
if ($record = $this->record_repository->save($input, $created_file)) {
unlink(app_path() . '/storage/bulk-upload/' . $file);
$this->images->deleteMediaFromTemporaryS3(array(array('Key' => $file )));
} else {
$data['filename'] = $file;
\Mail::send('emails.bulk-upload', $data, function($message) {
$message->to('email', 'Daniel Newns')->subject('Bulk upload save issue');
});
}
}
}
}
}
$parse = new \ParseRestClient();
$user = $parse->retrieveCurrentUser( $data['pid']);
if (isset($user->email)) {
$vehicle_url = \URL::route('vehicles.show', $data['vehicle_objectId']);
$body = "<p>Hi " . $user->username . "</p><p>Your records have all been created. View them all as part of your vehicle record <a href='" . $vehicle_url . "'>here</a></p>";
$message = array(
'to' => array(array('email' => $user->email)),
'from_email' => 'xxxxx
'from_name' => 'xxxxx'
);
$template_content = array(array("name" => "share", "content" => $body));
$response = \Email::messages()->sendTemplate('Bulk_Upload', $template_content, $message);
}
}
} catch(\Exception $e){
$message = array(
'to' => array(array('email' => 'email')),
'from_email' => 'email',
'from_name' => 'xxxxxx'
);
$content = '<p>'. $e->getMessage() . '</p>';
$content .= '<p>' . $e->getTraceAsString() . '</p>';
$template_content = array(array("name" => "share", "content" => $content));
$response = \Email::messages()->sendTemplate('Content_Share', $template_content, $message);
}
}
你可以看到它循环从队列返回的数据并从这里循环文件它从S3拉出图像并将其存储在本地然后它检查是否有日期设置并通过任一个计算出创建的日期那个或exif数据。然后它创建文件并将记录保存在保存功能中,它执行所需的所有大小调整。
我的问题是,其他人对我如何改进这一点有任何建议,因为我偶尔会收到来自异常的电子邮件,其中说它无法找到像本地未创建的某个图像,是我创建的方法使用我应该使用的file_put_contest
本地图像或者是否有更好的方法从S3中提取数据并使用它。我已经提出了一些if语句来阻止事情陷入困境等。
很高兴听到其他人对我在哪里出错的想法以及我可以做些什么来改善这一点?也许我可以存储一个在第一个循环中不存在的文件数组,然后再尝试,因为我认为可能是在图像存在之前执行代码的情况会是这种情况吗?
任何帮助都会非常感激。
感谢
答案 0 :(得分:0)
我很好奇你是如何实现处理图像的实际队列的?
当我过去需要进程队列时,我使用PHP创建了一个服务器守护程序,它将检查数据库是否有新映像。每次上传图像时,我都会将原件复制到临时位置,并将图像的名称和状态存储在数据库中。状态是新的,处理的和完整的。一旦服务器从db中获取要处理的文件,我就将状态更新为处理。
我还在我的每台机器上安装了一个S3存储桶,然后符号链接到本地文件夹,这样就可以访问所有文件而无需先下载文件。该代码的行为就像文件是本地文件一样,即使在后台正在下载图像。
但是,AWS服务中的另一个解决方案是他们的SQS(简单排队服务)。在应用程序中使用带有SQS API的S3 API,您可以完成尝试构建服务器守护程序时尝试执行的操作。
我会在此处查看此链接:http://aws.amazon.com/articles/1602?_encoding=UTF8&jiveRedirect=1
他们对如何使用上述服务完全按照您的要求做了很好的指导。他们建议使用dynamoDB,但您可以更换任何已使用的数据库。
无论您选择哪种路线,都需要数据库来跟踪文件,处理状态以及跟踪您的文件。如果您担心由于文件尚未下载而有时会遇到错误,我会检查以确保文件首先存在,如果它确实检查文件大小与DB,然后确定文件是否已准备好进行处理。您可以通过使用cron作业命中该特定URL来运行laravel中的脚本。
希望这有帮助!