Php Laravel:将大量任务放入队列

Php Laravel:将大量任务放入队列,php,laravel,laravel-5,Php,Laravel,Laravel 5,我正在使用Laravel 5构建一个web应用程序,该应用程序创建指向web应用程序的链接,当访问该应用程序时,会显示学生进度报告的表单。这些链接由web应用程序发送到学生所在院校联系人的电子邮件中,以便收件人完成电子邮件中链接访问的进度报告 我面临的问题是在创建和发送链接时。我有一些代码可以很好地处理几百名学生,但是在现实世界中,应用程序可能会一次创建和发送3000多个链接。我编写的代码无法及时处理如此大量的数据,应用程序崩溃。奇怪的是,尽管我没有通过laravel收到任何超时错误(我需要仔细

我正在使用Laravel 5构建一个web应用程序,该应用程序创建指向web应用程序的链接,当访问该应用程序时,会显示学生进度报告的表单。这些链接由web应用程序发送到学生所在院校联系人的电子邮件中,以便收件人完成电子邮件中链接访问的进度报告

我面临的问题是在创建和发送链接时。我有一些代码可以很好地处理几百名学生,但是在现实世界中,应用程序可能会一次创建和发送3000多个链接。我编写的代码无法及时处理如此大量的数据,应用程序崩溃。奇怪的是,尽管我没有通过laravel收到任何超时错误(我需要仔细检查php日志)

尽管我非常欢迎其他建议,但我相信问题的答案是利用排队。我在发送电子邮件时已经使用了队列(请参阅代码),但我想将代码的其他部分放入队列中,但我有点不确定如何做到这一点

简要数据库模式

学生
有许多
链接

学生
有许多
机构联系人
(根据我的申请限制为两个)

链接
有许多
机构联系人
(根据我的申请限制为两个)

电子邮件
manytomy
链接

我正在努力实现的目标

  • 获取所有需要新链接的
    学生

  • 为每个
    学生创建
    链接

  • 学生
    的当前
    机构联系人
    分配给
    链接
    机构联系人
    (学生
    的机构联系人可能会更改,因此如果需要重新发送,我会将
    机构联系人
    链接到该链接

  • 循环浏览所有新创建的
    链接
    ,以便通过共享
    机构联系人
    s将它们组合在一起-这样就不会每个链接发送一封电子邮件(因此可能会将多封带有一个链接的电子邮件发送到同一地址),而链接应通过相同的电子邮件/联系人分组在一起,并在适用的情况下一起发送

  • 循环浏览所有按电子邮件/联系人分组的
    链接,并:

  • 将包含
    链接的
    信息(url、学生姓名等)的电子邮件发送到指定的
    机构联系人的电子邮件地址
  • 电子邮件的副本写入数据库
  • 将在前一步中创建的
    电子邮件
    加入其中发送的
    链接
    (因此应用程序可用于搜索在哪个电子邮件中发送的链接)
因此,我面临的主要挑战是使用大型数据集执行上述任务。我已经考虑过通过队列逐个创建和发送
链接
,但这不允许我通过联系人/电子邮件将所有
链接
分组在一起。由于任务不会定期执行,我愿意考虑在发送任何链接之前,我尝试使用
set_time_limit(0);
ini_set('memory_limit','1056M');
按原样执行任务时,内存和时间都有所增加,但没有取得太大成功

任何帮助都将不胜感激,如果你读到这里,谢谢你

代码

app\Http\Controllers\LinkController.php

public function storeAndSendMass(Request $request)
{
    $this->validate($request, [
        'student_id' => 'required|array',
        'subject'    => 'required|max:255',
        'body'       => 'required|max:5000',
    ]);

    $studentIds = $request->get('student_id');
    $subject    = $request->get('subject');
    $body       = $request->get('body');

    $students = $this->student
        ->with('institutionContacts')
        ->whereIn('id', $studentIds)
        ->where('is_active', 1)
        ->get();

    // create link, see Link.php below for method
    $newLinks = $this->link->createActiveLink($students);

    // send link to student's contact(s), see LinkEmailer.php below for method
    $this->linkEmailer->send($newLinks, ['subject' => $subject, 'body' => $body], 'mass');

    // return
    return response()->json([
        'message' => 'Creating and sending links'
    ]);
}
public function createActiveLink($students)
{
    $links = [];

    foreach ($students as $student) {
        $newLink = $this->create([
            'token'          => $student->id, // automatically hashed
            'status'         => 'active',
            'sacb_refno'     => $student->sacb_refno,
            'course_title'   => $student->course_title,
            'university_id'  => $student->university_id,
            'student_id'     => $student->id,
            'institution_id' => $student->institution_id,
            'course_id'      => $student->course_id,
        ]);

        $studentContacts = $student->institutionContacts;

        if ($studentContacts) {

            foreach ($studentContacts as $studentContact) {

                $newLink->contacts()->create([
                    'type'                   => $studentContact->pivot->type,
                    'institution_contact_id' => $studentContact->pivot->institution_contact_id
                ]);

                $newLink->save();
            }

        }

        $links[] = $newLink->load('student');
    }

    return $links;
}
 // Accept request, validate $students

 // Send this work strait to the cue
 Bus::dispatch(
    new CreateActiveLinks($students));
 );

// return
return response()->json([
    'message' => 'Creating and sending links. This will take a while.'
]);
app\Models\Link.php

public function storeAndSendMass(Request $request)
{
    $this->validate($request, [
        'student_id' => 'required|array',
        'subject'    => 'required|max:255',
        'body'       => 'required|max:5000',
    ]);

    $studentIds = $request->get('student_id');
    $subject    = $request->get('subject');
    $body       = $request->get('body');

    $students = $this->student
        ->with('institutionContacts')
        ->whereIn('id', $studentIds)
        ->where('is_active', 1)
        ->get();

    // create link, see Link.php below for method
    $newLinks = $this->link->createActiveLink($students);

    // send link to student's contact(s), see LinkEmailer.php below for method
    $this->linkEmailer->send($newLinks, ['subject' => $subject, 'body' => $body], 'mass');

    // return
    return response()->json([
        'message' => 'Creating and sending links'
    ]);
}
public function createActiveLink($students)
{
    $links = [];

    foreach ($students as $student) {
        $newLink = $this->create([
            'token'          => $student->id, // automatically hashed
            'status'         => 'active',
            'sacb_refno'     => $student->sacb_refno,
            'course_title'   => $student->course_title,
            'university_id'  => $student->university_id,
            'student_id'     => $student->id,
            'institution_id' => $student->institution_id,
            'course_id'      => $student->course_id,
        ]);

        $studentContacts = $student->institutionContacts;

        if ($studentContacts) {

            foreach ($studentContacts as $studentContact) {

                $newLink->contacts()->create([
                    'type'                   => $studentContact->pivot->type,
                    'institution_contact_id' => $studentContact->pivot->institution_contact_id
                ]);

                $newLink->save();
            }

        }

        $links[] = $newLink->load('student');
    }

    return $links;
}
 // Accept request, validate $students

 // Send this work strait to the cue
 Bus::dispatch(
    new CreateActiveLinks($students));
 );

// return
return response()->json([
    'message' => 'Creating and sending links. This will take a while.'
]);
app\Emails\LinkEmailer.php

public function storeAndSendMass(Request $request)
{
    $this->validate($request, [
        'student_id' => 'required|array',
        'subject'    => 'required|max:255',
        'body'       => 'required|max:5000',
    ]);

    $studentIds = $request->get('student_id');
    $subject    = $request->get('subject');
    $body       = $request->get('body');

    $students = $this->student
        ->with('institutionContacts')
        ->whereIn('id', $studentIds)
        ->where('is_active', 1)
        ->get();

    // create link, see Link.php below for method
    $newLinks = $this->link->createActiveLink($students);

    // send link to student's contact(s), see LinkEmailer.php below for method
    $this->linkEmailer->send($newLinks, ['subject' => $subject, 'body' => $body], 'mass');

    // return
    return response()->json([
        'message' => 'Creating and sending links'
    ]);
}
public function createActiveLink($students)
{
    $links = [];

    foreach ($students as $student) {
        $newLink = $this->create([
            'token'          => $student->id, // automatically hashed
            'status'         => 'active',
            'sacb_refno'     => $student->sacb_refno,
            'course_title'   => $student->course_title,
            'university_id'  => $student->university_id,
            'student_id'     => $student->id,
            'institution_id' => $student->institution_id,
            'course_id'      => $student->course_id,
        ]);

        $studentContacts = $student->institutionContacts;

        if ($studentContacts) {

            foreach ($studentContacts as $studentContact) {

                $newLink->contacts()->create([
                    'type'                   => $studentContact->pivot->type,
                    'institution_contact_id' => $studentContact->pivot->institution_contact_id
                ]);

                $newLink->save();
            }

        }

        $links[] = $newLink->load('student');
    }

    return $links;
}
 // Accept request, validate $students

 // Send this work strait to the cue
 Bus::dispatch(
    new CreateActiveLinks($students));
 );

// return
return response()->json([
    'message' => 'Creating and sending links. This will take a while.'
]);
编辑1

我现在已经用
set\u time\u limit(0);
ini\u set('memory\u limit','1056M');
花了8分钟完成3000名学生

编辑2

我正在运行Laravel框架版本5.1.6(LTS),MySQL for DB

编辑3

感谢所有的答案,谢谢大家。我想我可以将
链接
创建过程放入一个队列中,该队列在数据库中有一个类似
Batch
的相关实体,当链接的
Batch
创建完成后,将所有
链接
B分组atch
并发送它们


我可以使用@denis mysenko建议的方法,在
链接
的表中设置一个
sent_
字段,并安排一个流程来检查尚未发送的
链接
然后发送它们。然而,使用上述方法,我可以在链接
批处理
完成后发送它们已完成创建,而使用
sent_at
方法,通过计划进程查找尚未发送的
链接,当所有链接尚未创建时,它可能会发送一些链接。

如果您使用少量数据测试了代码,并且成功而没有崩溃,那么很明显,pr问题是(正如您所说)您处理的记录数量相当多。为什么不使用chunk方法处理您的收集

根据Laravel文件:

如果需要处理数千条雄辩记录,请使用chunk命令。chunk方法将检索雄辩模型的“chunk”,并将其提供给给定的闭包进行处理。在处理大型结果集时,使用chunk方法将节省内存

无论如何,我认为在这种情况下需要使用队列。我认为,由于请求超时的高风险,应该绝对避免在HTTP请求上处理大量数据。排队过程没有执行时间的限制

为什么不在集合中同时使用queue和chunk方法呢