如何使用Laravel Queues创建/使用php类的单个实例

时间:2019-07-12 23:04:12

标签: php laravel singleton

很抱歉,这个时间太长了,但不确定如何解决我的问题。

我正在使用Laravel 5.8和php 7.2。* 我有一个像这样的php类:

class PushNotificationsJob implements ShouldQueue

这用于将推送通知发送到移动设备,并且在大多数情况下目前运行良好。 由于Apple的限制,他们不希望您一遍又一遍地连接和断开连接,如果您在短时间内执行了太多次,他们将返回拒绝服务(DOS)。因此,两个设计问题中的第一个是我需要能够保存卷曲连接以供反复使用。现在我连接,发送通知,然后断开连接。问题在于,指示何时需要发送通知的事件是不可预测的,也无法控制。我现在遇到的第二个设计问题是我确实需要创建一个表,其中包含每种通知类型的每个移动设备的记录。我需要执行此操作的主要原因是,我需要将发送某种类型的通知的时间推迟到15秒,而无需再次将该通知类型发送给该移动设备。因此,我遇到的问题是,如果每次我排队运行PushNotificationsJob类时,它都运行一个不同的实例,那么我可能最终会同时运行两个实例,并且两者都可以查询相同的记录,并且在发送时都发送相同的通知应该只发送一次。

当然,我使用队列的原因是减轻了从主线程发送通知的过程,因此它不会减慢对客户端的响应。

我有一种感觉,如果人们不了解为什么这种方法会起作用,那么他们会建议一些不适用的选项,因此,如果您需要其他信息,我会在此处添加详细信息。发生的事情是我有几千个摄像头,当它们检测到运动并上传到我的服务器时正在拍照。我无法控制他们何时检测到运动并上载。当相机通过REST API上传照片时,我需要提供该相机的所有者并向他们发送通知。 (还有其他一些因素会导致发送通知,但这是最好的例子),因此问题是相机可能有1张照片或50张照片要上传。用户希望尽快收到通知。如果相机要上传的照片多于1张,通常只需要5-8秒即可上传下一张照片。因此,我想做的是将第一条通知的发送时间延迟15秒,但是如果在发送第一条通知之前上传了另一张照片,那么我想将通知的计时器重设15秒。因此,一旦照相机超过15秒而没有上传照片,那么我会发送一条通知而不是50。

我的想法是,如果我能够以某种方式创建在另一个线程中运行的Class的单​​个实例,并且每次需要发送“推送通知”时,我都会通过调用某种方法来告诉它来“唤醒”该类他们是活动。然后,它可以重新查询表并处理那些“准备好”要发送的记录。这将解决这两个问题,该实例可以保持与Apple的单个curl连接,并且由于只有一个实例,它可以自由地查询记录并进行处理并在完成后删除,而不必担心与执行该操作的另一个实例冲突。同样的事情。

1 个答案:

答案 0 :(得分:1)

这很有趣,我喜欢这个概念。

您如何设置队列工作者?如果您使用主管来管理您的工作人员,那么这应该是一个长期运行的过程。这就是为什么每次更改代码库都必须调用artisan queue:restart的原因。众所周知,我忘记了这一点,最终想知道为什么更改无效,因此将头发撕掉了。

由于这个事实,我想您可以将单例绑定到服务容器并在需要工作时调用它。 CURL连接将存储在单例中,您可以在服务提供商中注册。创建新连接的唯一时间是队列工作器是否死亡并重新启动。

当然,您需要解决此问题,使其仅从队列工作器运行,而不是每次启动应用程序时都运行。

编辑:在创建连接并绑定单例之前,我添加了一项检查以确保应用程序正在从控制台运行(就像队列工作器一样)。我不知道如何仅对队列工作者执行此操作,但是如果我发现了,我会通知您。目前,您只需要了解其他工匠命令即可。

App / Providers / AppServiceProvider.php

use App;

class AppServiceProvider extends ServiceProvider
{
    public function register()
    {
        // make sure we're running from the console 
        // and not every time the app is booted
        if (App::runningInConsole()) {

            // create your connection
            $connection = new YourCurlConnection();

            $this->app->singleton('App\Support\PushNotificationHelper', function ($app) use ($connection) {
                return new App\Support\PushNotificationHelper($connection);
            });
        }
    }
}

App \ Support \ PushNotificationHelper.php

class PushNotificationHelper
{
    // your CURL instance
    protected $connection;

    public function __construct($connection)
    {
        // store via dependency injection
        $this->connection = $connection;
    }

    public function sendNotification($message)
    {
        // send notification using stored connection
    }
}

App / Jobs / PushNotificationsJob.php

class PushNotificationsJob implements ShouldQueue
{
    protected $message;

    public function __construct($message)
    {
        $this->message = $message;
    }

    public function handle()
    {
        $message = $this->message;

        // get the singleton
        $helper = app('App\Support\PushNotificationHelper');

        // send the message using the singleton
        $helper->sendNotification($message);
    }
}

当然,如果您不希望重叠的连接,则需要确保 supervisor 仅运行一个队列工作程序,因为我认为文档在默认配置中列出了八个工作程序。

还有一点需要注意的是,您可能希望偶尔通过调度程序触发队列的重新启动,以确保您不会在此过程中占用过多的内存。

我希望这能给您一些想法和好运!