Laravel:检查是不是有新项目添加到 db 表并安排一个工作给用户发送电子邮件

Posted

技术标签:

【中文标题】Laravel:检查是不是有新项目添加到 db 表并安排一个工作给用户发送电子邮件【英文标题】:Laravel: Check if new items added to db table and schedule a job to email userLaravel:检查是否有新项目添加到 db 表并安排一个工作给用户发送电子邮件 【发布时间】:2019-11-23 17:01:05 【问题描述】:

我想在我的 Laravel 应用程序的表中添加新行时触发一封电子邮件。但是我想添加一个缓冲区,所以如果快速连续添加 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 和 Project 模型之间的关系。正如我在代码中评论的那样,我不会详细说明。

问题

当我在 JobItem 表中添加新行时,我可以看到作业已被安排和处理(使用 Laravel Telescope 来检查)。

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

首先:“失败”,然后是“Activity Job Run

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

看来是onFailure被触发了,我的ProcessActivity有问题。

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

【问题讨论】:

我认为你的逻辑也有问题。您每分钟运行一次计划。这意味着已经处理的行将在接下来的 19 分钟循环中再次处理。 @sachinkumar 啊!我现在只是为了调试目的而每分钟都在运行 - 我会进去修改它,以免混淆! 你能弄清楚抛出了什么异常吗? 任何想法如何@kevin - 我如何在 onFailure() 中转储异常? 请在你的工作中放置一个 try catch 并记录异常:try catch (\Exception $e) \Log::info($e->getMessage()); 【参考方案1】:

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

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

php artisan queue:work

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

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

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 方法。所以我不得不把我雄辩的查询移到handle方法中。

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

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

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

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

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

我仍然对这表明什么以及如何确定有关它如何失败以及这意味着什么的更多信息感到困惑。但是,它确实有效,所以我会小心翼翼地继续前进(睁大一只眼睛盯着 cmets,以防有人有可以提供帮助的想法!)

【讨论】:

您是否启动了调度程序?如果调度程序运行,那么它也不会反映更改。

以上是关于Laravel:检查是不是有新项目添加到 db 表并安排一个工作给用户发送电子邮件的主要内容,如果未能解决你的问题,请参考以下文章

如何从 db 中的两个表中路由、获取和显示数据到 laravel 5.2 中的单个网页

Laravel 4 db 种子特定播种器文件

Laravel 多数据库连接连接表

检查 belongsToMany 关系是不是存在 - Laravel

来自DB的Laravel雄辩错误选择数据

从 db 获取数据到 laravel 5.2 中的视图的问题