【发布时间】:2017-07-16 20:50:28
【问题描述】:
我有一个作为纯 API 应用程序运行的 Laravel 5.3 安装,需要从多个不同的应用程序连接。
一切正常(毕竟我们谈论的是 Laravel :P),除了我无法弄清楚一件事:
我有一个 MQTT 服务器,它正在侦听来自多个设备的消息(不管是什么)。这些消息包含有关需要在后端调用的作业类和方法的信息。
我不能直接调用 API,设备根本不支持这个(他们支持,但比使用 MQTT 传输数据要努力得多)。我的想法是将新作业推送到定义要调用哪个 Laravel 作业类(以及哪个方法)的队列中。问题在于 JSON 序列化...
MQTT 服务器在 NodeJS 上运行,我的队列在 Redis 上运行。我记得 Taylor 的一条推文,他提到理论上可以序列化所需的 JSON 并从 Laravel 外部推送到队列,并让 Laravel 处理工作。
有人知道如何解决这个问题吗?是否有关于 JSON 结构的文档?
我还应该提到这个解决方案NodeJS push queue, consumed by Laravel worker 对我不起作用。与上面的结果相同,作业被放入队列但没有被处理或抛出任何错误就被丢弃了。
Redis 中排队事件的示例数据结构如下所示:
"{\"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}"
基于该结构,我认为对象(需要序列化)应该类似于:
{
"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 实际放入队列的内容中包含其他信息(如时间戳、用户模型标识符等),但我认为这不是触发工作所必需的。
数据需要在 JS 中进行序列化,以实现与 php serialize() 类似的输出(或者更好,以获得可以通过 php 的 unserialize() 进行反序列化的字符串。
我通过 php-serialization NPM 模块实现了这一点(感谢 Simon Svensson),但 Laravel 仍然没有使用该作业(已丢弃但未执行)
提前感谢您的帮助:)
编辑解决方案
感谢 Simon 的回答,这是关于如何在 Javascript 中序列化作业数据并推送到 Laravel 队列(并让 Laravel 自动处理整个事情)的解决方案。
请注意,这是在 Redis 中使用队列的示例。当使用 Beanstalkd 或基于数据库的队列时,这可能看起来不同(或不同)。
这是我成功使用的代码:
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 个字符,我认为保持这个长度是个好主意)。
最初推送作业时应将尝试次数设置为 1。如果 Laravel 无法处理该作业,它会将其推回队列并增加尝试次数。
【问题讨论】:
-
如果我的最新更新没有解决您的问题,并且您仍然需要帮助调试队列(这可能涉及将调试语句添加到 vendor/laravel/framework 文件夹中),请尝试在 IRC(@ 987654325@) 或 Slack (larachat.co)。
-
反对票是为了什么?解决在其他任何地方都没有答案的问题?
-
我赞成你的问题 Jan - 我很高兴我不是唯一一个尝试这样做的人 :)
标签: javascript node.js laravel redis queue