我有一个 Laravel 5.3 安装作为纯 API 应用程序运行,需要从多个不同的应用程序进行连接。
一切都工作正常(毕竟我们谈论的是 Laravel :P),除了我不明白一件事:
我有一个 MQTT 服务器,它正在侦听来自多个设备的消息(无论是什么)。这些消息包含有关需要在后端调用的作业类和方法的信息。
我无法直接调用API,设备根本不支持这一点(他们支持,但这比使用MQTT传输数据要费力得多)。我的想法是将一个新作业推送到队列中,定义要调用哪个 Laravel 作业类(以及哪个方法)。问题是 JSON 序列化...
MQTT 服务器在 NodeJS 上运行,我的队列在 Redis 上运行。我记得 Taylor 在推文中提到,理论上可以序列化所需的 JSON 并从 Laravel 外部推送到队列,然后由 Laravel 处理作业。
有人知道如何解决这个问题吗?有没有关于 JSON 结构的文档?
我还应该提到这个解决方案NodeJS 推送队列,由 Laravel Worker 消耗 https://stackoverflow.com/questions/32720428/nodejs-push-queue-consumed-by-laravel-worker?rq=1不适合我。与上面的结果相同,作业被放置在队列中,但在没有被处理或抛出任何错误的情况下被丢弃。
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 类似的输出连载() http://php.net/manual/en/function.serialize.php(或者更好的是,获得一个可以被 php 反序列化的字符串反序列化() http://php.net/manual/en/function.unserialize.php.
我通过 php-serialization NPM 模块实现了这一点(感谢西蒙·斯文森 https://stackoverflow.com/users/73744/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 无法处理该作业,它会将其推回队列并增加尝试值。