Laravel:检查是否有新项目添加到数据库 table 并安排一个作业给用户发邮件

Laravel: Check if new items added to db table and schedule a job to email user

我想在 Laravel 应用程序中的 table 添加新行时触发电子邮件。但是我想添加一个缓冲区,所以如果快速连续添加 5 行,则只发送 1 封电子邮件。

我选择的方法是每 15 分钟安排一次检查,看看是否添加了新行。如果有那么我会排队发送电子邮件。

目前我在日程安排上遇到了错误。我将 运行 通过下面的代码:

Kernel.php 中,我们设置了时间表:

        $schedule->job(new ProcessActivity)
        ->everyFifteenMinutes()
        ->when(function () {
            return \App\JobItem::whereBetween('created_at', array(Carbon::now()->subMinutes(15), Carbon::now()))->exists();
        })
        ->onSuccess(function () {
            Log::debug(
                'Success'
            );
        })
        ->onFailure(function () {
            Log::debug(
                'Fail'
            );
        });

我用它来触发在以下位置找到的作业:App\Jobs\ProcessActivity。php :

 public function __construct()
{

    $this->jobs = \App\JobItem::whereBetween('created_at', array(Carbon::now()->subMinutes(15), Carbon::now()))->get();
}

/**
 * Execute the job.
 *
 * @return void
 */
public function handle()
{


    Log::debug('Activity Job Run',  ['jobs' => $this->jobs]);

    $this->jobs->each(function ($item, $key) {
        Log::debug('loop');

        // get project
        $project = $item->project;

        // get project email
        $user_id = $project->user_id;
        $email = \App\User::find($user_id)->email;

        // get project UUID
        $projectUuid = $project->public_id;

        // emails
        $subscriberEmails = \App\ProjectSubscription::where('project_id', $project->id)->get();

        // create activity email
        Notification::route('mail', $subscriberEmails)->notify(new Activity($project, $projectUuid));
    });

    return true;
}

我已经在上面发布了我的完整代码,其中还显示了我的 JobItems 和项目模型之间的关系。正如我在代码中评论的那样,我不会对此进行详细说明。

问题

当我向我的 JobItem 添加新行时 table 我可以看到该作业已安排并处理(使用 Laravel Telescope 进行检查)。

但是,我还可以在我的日志中看到,对于每个作业,我都会收到两条日志消息:

首先:“失败”,然后是“Activity作业运行

我的电子邮件未发送,我不确定如何确定失败的原因。

看来是触发了onFailure,我的进程有问题Activity。

任何关于我哪里出错以及如何确定错误的线索都将不胜感激。

我有解决办法,但首先,我了解到一些阻碍我进步的事情:

我正在使用这个 artisan 命令来处理我的预定作业:

php artisan queue:work

使用该命令进行开发的问题是,如果有代码更改,则无法识别这些更改。

因此您可以通过 Command+C 到 return 到控制台,并在每次代码更改时使用它:

php artisan queue:restart
php artisan queue:work

或者您可以只使用它,它将允许更改代码:

php artisan queue:listen

正如您可以想象的那样,如果您不知道这一点,您的调试过程将会很慢!

因此,在我的工作中添加了一个例外,我取得了一些进展。我将粘贴下面的代码以与原始代码进行比较:

    public function __construct()
{
}

/**
 * Execute the job.
 *
 * @return void
 */
public function handle()
{
    try {

        $jobs = \App\JobItem::whereBetween('created_at', array(Carbon::now()->subMinutes(20), Carbon::now()))->get();

        Log::debug('Activity Job',  ['jobs' => $jobs]);

        // collection start
        $collection = collect();

        // loop jobs to get emails
        foreach ($jobs as $key => $value) {

            // get project UUID
            $project = $value->project;
            $projectUuid = $project->public_id;

            // get emails subscribed to projects
            $subscriberEmails = \App\ProjectSubscription::where('project_id', $project->id)->get();

            // merge into a single collection via the loop
            if ($key != 0) {
                $merge = $collection->merge($subscriberEmails);
                $collection = collect($merge);
            } else {
                $collection = $subscriberEmails;
            }

            // Log::debug('emails_project in loop', ['emails' => $subscriberEmails]);
        };

        // clean object with uniques only
        $subscriberEmailsCleaned = $collection->unique();

        // debug
        Log::debug('Project Emails to Notify', ['emails' => $subscriberEmailsCleaned]);

        // create activity email
        Notification::route('mail', $subscriberEmailsCleaned)->notify(new Activity($project, $projectUuid));
    } catch (\Exception $e) {
        \Log::info($e->getMessage());
    }
}

首先要注意的是,__construct() 最初是 运行 并且是序列化的。然后在处理作业时调用 handle 方法。所以我不得不将我的 eloquent 查询移动到 handle 方法中。

我还使用 foreach 而不是 .each 循环遍历并创建新的电子邮件集合。也许有更优雅的方法,但我需要创建一个电子邮件集合,这种方法允许我将循环中的变量移到外部以在方法中使用。

你可以看到我在循环的底部合并了这些。

我还添加了一些对调试有用的 Log:: 项。

未修复 100% 使用此代码,我现在可以在添加新项目时每 x 分钟自动安排一封电子邮件。但是,我仍然从我的 Kernal.php 文件中的 onFailure() 获取日志失败:

        ->onFailure(function () {
        Log::debug(
            'Fail'
        );

我仍然对这表明什么以及如何确定有关失败原因和含义的更多信息感到困惑。然而,它确实有效,所以我会谨慎地前进(睁大眼睛看评论,以防有人有想法可以提供帮助!)