2

大家好,我只是有一个关于最佳实践的快速问题,也许对排队和图像处理有一些帮助。

我目前在一个网站上工作,该网站允许用户一次上传超过 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 计算出创建日期数据。然后它创建文件并将记录保存在 save 函数中,它执行所有需要的调整大小。

我的问题是真的有人对我如何改进这一点有任何建议,因为我偶尔会收到来自异常的电子邮件,它说它找不到某个图像,就像它没有在本地创建一样,是我在本地创建图像的方法使用file_put_contest我应该使用的那个,或者有更好的方法让我从 S3 中提取数据并使用它。我已经放入了一些 if 语句来阻止事情通过差距等。

很高兴听到其他人对我在哪里出错以及我可以做些什么来改善这一点的想法?也许我可以存储在第一个循环中不存在的文件数组,然后再试一次,因为我认为这可能是在图像存在之前执行的代码的情况会是这种情况吗?

任何帮助将非常感激。

谢谢

4

1 回答 1

1

我很好奇你是如何实现处理图像的实际队列的?

当我过去需要一个进程队列时,我使用 PHP 创建了一个服务器守护程序,它会检查数据库中的新图像。每次上传图像时,我都会将原始图像复制到临时位置,并将图像的名称和状态存储在数据库中。状态是新的、处理中的和完整的。一旦服务器从数据库中获取要处理的文件,我就会将状态更新为正在处理。

我还在我的每台机器上安装了一个 S3 存储桶,然后符号链接到本地​​文件夹,这样所有文件都可以访问,而无需先下载文件。代码的行为就像文件是本地文件一样,即使在后台下载图像也是如此。

然而,存在于 AWS 服务中的另一个解决方案是他们的 SQS(简单排队服务)。在您的应用程序中使用 S3 API 和 SQS API,您可以完成您尝试做的事情,而无需尝试构建服务器守护程序。

我会在这里查看这个链接:http ://aws.amazon.com/articles/1602?_encoding=UTF8&jiveRedirect=1

他们有一个很好的指南,告诉你如何使用上面的服务来做你想做的事情。他们建议使用 dynamoDB,但您可以换掉任何您已经在使用的数据库。

无论您走哪条路,您都需要一个数据库来跟踪文件和处理状态,并在一般情况下跟踪您的文件。如果您担心由于文件尚未下载而有时会遇到错误,我会先检查以确保文件存在,如果确实检查了 DB 的文件大小,然后确定文件是否已准备好进行处理。您也可以通过使用 cron 作业点击该特定 url 在 laravel 中运行脚本。

希望这可以帮助!

于 2014-04-23T05:25:20.773 回答