从Laravel外部推送到Laravel队列(NodeJS) [英] Push to Laravel queue from outside Laravel (NodeJS)

查看:80
本文介绍了从Laravel外部推送到Laravel队列(NodeJS)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个Laravel 5.3安装作为纯API应用程序运行,需要从几个不同的应用程序连接。

I have a Laravel 5.3 installation running as a pure API application and need to connect from several different applications.

一切正常(毕竟它是Laravel我们'重新讨论:P),除了我无法弄清楚一件事:

Everything is working fine (after all it's Laravel we're talking about :P), except I can't figure out one thing:

我有一个MQTT服务器正在监听来自多个设备的消息(无关紧要)什么)。这些消息包含有关需要在后端调用的Job类和方法的信息。

I have a MQTT server that is listening for messages from several devices (doesn't matter what). These messages contain information about a Job Class and method that need to be called on the backend.

我无法直接调用API,设备根本不支持这(他们这样做,但比使用MQTT传输数据要多得多)。我的想法是将一个新工作推入队列,定义要调用哪个Laravel Job Class(以及哪个方法)。问题是JSON序列化......

I can't call the API directly, the devices simply don't support this (they do, but it's a lot more effort than using MQTT to transmit data). My thought was to push a new job onto the queue defining which Laravel Job Class to call (and which method). The problem is the JSON serialization...

MQTT服务器在NodeJS上运行,我的队列在Redis上运行。我记得泰勒发来的一条推文,他提到理论上可以将所需的JSON序列化并从Laravel外部推送到队列,然后由Laravel处理。

The MQTT server is running on NodeJS, my queues are running on Redis. I remember a Tweet from Taylor where he mentioned that theoretically it could be possible to serialize the JSON needed and push to the queue from outside Laravel, and have the job processed by Laravel.

任何人都知道如何处理这个问题?是否有关于JSON结构的文档?

Anyone any idea how to approach this? Is there a documentation available about the structure of the JSON?

我还应该提一下这个解决方案 Laravel worker消耗的NodeJS推送队列对我不起作用。与上面相同的结果是,作业被放置在队列中但被丢弃而没有被处理或抛出任何错误。

I should also mention that this solution NodeJS push queue, consumed by Laravel worker did not work for me. Same result as above, the job is placed on the queue but discarded without being processed or any errors thrown.

Redis中排队事件的示例数据结构如下所示:

The sample data structure for a queued Event in Redis looks like this:

{\job \:\照亮\\\\Broadcasting \\\\ \\\BroadcastEvent\,\ data\:{\ event\:\ ○:28:\\\ App\\\\Events\\ \\\\\NotificationEvent\\\ :5:{S:7:\\\ \\\\ * \\\\name\\\; S :12:\\\ notification\\\; S:4:\\\ data\\\;一个:4:{S:4:\ \\ testkey\\\; S:14:\\\ testval\\\; S:9:\\\timestamp\\ \; s:19:\\\2017-02-24 11:07:48 \\\; s:5:\\\event'\\ \\ ; S:12:\\\ notificat ion\\\ ; S:5:\\\ class\\\ ; S:28:\\\ App\\\\Events \\\\NotificationEvent\\\ ;} S:10:\\\ \\\\ * \\\\channel\\\; N; S:7:\\\ \\\\ * \\\\user\\\,O:45:\\\Illuminate\\\\ Contracts\\\\Database\\\\ModelIdentifier\\\ :2:{S:5:\\\ class\\\; S:8:\\\ App\\\\User\\\; S:2:\\\ id\\\ 我:2;} S:6:\\\ socket\\\; N;} \ },\ id\ :\ XuUKRTf8CTSdzaVgp2gRcvmxQqLcpBUG\,\ attempts \:1}

基于该结构,我认为对象(需要序列化)应该看起来类似于:

Based on that structure, I would think the object (that needs to be serialized) should look similar to this:

{
"job":"EventClass@method", //<-- Just a name
"data":{
    "event":"EventClass", //<-- Just a name
    "name":"EventName", //<-- Just a name
    "data":{
    "key":"value"
    "event":"EventName" //<-- Same as data.name
    "class":"EventClass@method" //<-- This is actually being called
    }
}

Laravel实际放入队列中还包含其他信息(像时间戳,用户模型标识符等),但我不认为有必要触发这项工作。

There is additional information included in what Laravel actually puts on the queue (like a timestamp, user model identifier, etc), but I don't think that's necessary to trigger the job.

数据需要在JS中序列化以实现与php相似的输出 serialize()(或更好,获取字符串可以通过php的 unserialize()进行反序列化。

The data needs to be serialized in JS to achieve a similar output than with php serialize() (or better, to get a string that can be unserialized by php's unserialize().

我实现了这样做php-serialization NPM模块(感谢 Simon Svensson ),但这项工作仍然没有被Laravel(丢弃但未执行)

I achieved to do so with the php-serialization NPM module (Thanks to Simon Svensson), but the job still isn't being consumed by Laravel (discarded but not executed)

预先感谢您的任何帮助:)

Thanks in advance for any help :)

编辑解决方案

感谢Simon的回答,这里有关于如何在Javascript中序列化作业数据并推送到Laravel队列的解决方案(并让Laravel自动处理整个事情) )。

Thanks to Simon's answer, here's the solution on how to serialize job data in Javascript and push onto a Laravel queue (and have Laravel process the whole thing automatically).

请注意,这是使用Redis队列的示例。使用Beanstalkd或基于数据库的队列时,这可能看起来不同(或不是)。

Note that this is an example for using queues with Redis. When using Beanstalkd or Database based queues, this might look different (or not).

这是我成功使用的代码:

This is the code I successfully used:

var serialize,Class,job,jobUser,jobData,serialized,result;

serialize = require('php-serialization').serialize;
Class = require('php-serialization').Class;

job = new Class("App\\Events\\NotificationEvent");

job.__addAttr__("name","string","notification","string","protected");

jobData = new Class();
jobData.__addAttr__("testkey","string","testval","string");
jobData.__addAttr__("timestamp","string","2017-02-24 11:07:48","string");
jobData.__addAttr__("event","string","notification","string");
jobData.__addAttr__("class","string","App\\Events\\NotificationEvent","string");
job.__addAttr__("data","string",jobData,"array","public");

job.__addAttr__("channel","string",null,"null","protected");

jobUser = new Class("Illuminate\\Contracts\\Database\\ModelIdentifier")
jobUser.__addAttr__("class","string","App\\User","string","public");
jobUser.__addAttr__("id","string",2,"integer","public");
job.__addAttr__("user","string",jobUser,"object","protected");

job.__addAttr__("socket","string",null,"null","public");

serialized = serialize(job,"object");

result = {
    job:"Illuminate\\Broadcasting\\BroadcastEvent",
    data:{
        event:serialized
    },
    id:"XuUKRTf8CTSdzaVgp2gRcvmxQqLcpBUG",
    attempts:1
};

queue.rpush('queues:default',JSON.stringify(result));

我还没弄清楚ID到底是什么,我成功将作业推送到队列中总是一样的Id。我想如果你正在快速推动工作并且他们同时存储它可能是一个问题。因为它是一个字符串,你可以用你喜欢的任何随机ID替换它(Laravel生成的随机ID是32个字符,我认为保持这个长度是个好主意。)

I haven't figured out yet what the ID is exactly for, I successfully pushed jobs onto the queue with always the same Id. I guess if you're pushing jobs at a fast pace and they are stored at the same time it could be a problem. Since it's a string you could substitute it with any random ID you like (the random ID generated by Laravel is 32 characters, I think it's a good idea to keep this length).

初次推送作业时,尝试次数应设置为1。如果Laravel无法处理该作业,它会将其推回队列并增加尝试值。

Attempts should be set to 1 when initially pushing the job. If Laravel can't process the job, it will push it back onto the queue and increase the attempts value.

推荐答案

首先,请注意,这是Laravel 5.3中基于数据库的队列中作业的格式。较新版本的Laravel包含更改。

First, note that this is the format of the jobs in the database-based queue in Laravel 5.3. Newer versions of Laravel contains changes.

有效内容列应包含以下格式的json对象。在这种情况下,作业( ... \\CallQueuedHandler @ call )可以进行硬编码。我相信commandName键仅用于显示目的。但是,命令键是更难的部分,它应该是的有效对象。 unserialize()支持。为了这个目的,看起来npm上有可用的软件包,快速搜索了 php-serialization

The payload column should contain a json object of the following format. The job (...\\CallQueuedHandler@call) can be hard-coded in this scenario. I believe the commandName key is for display-purposes only. The command key, however, is the harder part, it should be a valid object that unserialize() supports. It looks like there are packages available on npm for this purpose, a quick search turned up php-serialization.

{
    "job": "Illuminate\\Queue\\CallQueuedHandler@call",
    "data": {
        "commandName": "App\\Jobs\\MyJobClass",
        "command": "O:19:\"App\\Jobs\\MyJobClass\"... /* stuff */"
    }
}






您提供的json有效负载会产生以下对象。作业和数据键都很重要。


The json payload you've provided results in the following object. Both the job and the data keys are important.

{
  "job": "Illuminate\\Broadcasting\\BroadcastEvent",
  "data": {
    "event": "O:28:\"App\\Events\\NotificationEvent\":5:{s:7:\"\u0000*\u0000name\";s:12:\"notification\";s:4:\"data\";a:4:{s:4:\"testkey\";s:14:\"testval\";s:9:\"timestamp\";s:19:\"2017-02-24 11:07:48\";s:5:\"event\";s:12:\"notification\";s:5:\"class\";s:28:\"App\\Events\\NotificationEvent\";}s:10:\"\u0000*\u0000channel\";N;s:7:\"\u0000*\u0000user\";O:45:\"Illuminate\\Contracts\\Database\\ModelIdentifier\":2:{s:5:\"class\";s:8:\"App\\User\";s:2:\"id\";i:2;}s:6:\"socket\";N;}"
  },
  "id": "XuUKRTf8CTSdzaVgp2gRcvmxQqLcpBUG",
  "attempts": 1
}

有问题的部分,我认为,是序列化的对象。重新格式化的方式更容易阅读(但完全打破了它)......

The problematic part, I presume, is the serialized object. Reformatted in a way that is easier to read (but totally breaks it) ...

O:28:"App\Events\NotificationEvent":5:{
    // protected $name = 'notification'
    s:7:" * name";s:12:"notification";

    // public $data = array(...)
    s:4:"data";a:4:{
        // 'testkey => 'testval'
        s:4:"testkey";s:14:"testval";

        // 'timestamp' => '2017-02-24 11:07:48';
        s:9:"timestamp";s:19:"2017-02-24 11:07:48";

        // 'event' => 'notification';
        s:5:"event";s:12:"notification";

        // 'class' => App\Events\NotificationEvent::class;
        s:5:"class";s:28:"App\Events\NotificationEvent";
    }

    // protected $channel = null;
    s:10:"\0*\0channel";N;

    // protected $user = (instance of ModelIdentifier)
    s:7:"\0*\0user";O:45:"Illuminate\Contracts\Database\ModelIdentifier":2:{
        // public $class = App\User::class;
        s:5:"class";s:8:"App\User";

        // public $id = 2;
        s:2:"id";i:2;
    }

    // public $socket = null;
    s:6:"socket";N;
}

此格式暴露了您的作业使用SerializesModels特征替换对模型作为包含类+标识符的简单条目,并将在__wakeup期间恢复它们。

This format exposes the fact that your job uses the SerializesModels trait that replaces references to models as a simple entry containing class+identifier, and will restore them during __wakeup.

我相信你的问题是json和serialize格式的心理解析;你推测的结构是错误的。

I believe your issue is with the mental parsing of the json and the serialize format; your guessed structure is ... wrong.

接下来的步骤不是猜测任何东西。
1.复制您已经拥有有效负载的确切测试通知。只需复制粘贴即可。 (您可能需要更改id,我猜它用于重复数据删除。)
2.使用php-serialization构建事件数据,目的是构建与原始事件有效负载相同的内容。完全没有变化。
3.如果它工作到目前为止,请随时更改序列化的事件数据,看看会发生什么。

The next steps would not be to guess anything. 1. Duplicate this exact test notification you already have the payload for. Just copy-paste it. (You may need to change the id, I guess it is used for deduplication.) 2. Build the event data using php-serialization and aim to build something identical to the original event payload. No changes at all. 3. If it works this far, feel free to change the serialized event data to see what happens.

这篇关于从Laravel外部推送到Laravel队列(NodeJS)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆