从Laravel外部(NodeJS)推送到Laravel队列
我有一个作为纯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实际放入队列的内容中包含其他信息(例如时间戳,用户模型标识符等,但我认为触发该作业不是必需的。
[与php serialize()相比,数据需要在JS中进行序列化以实现类似的输出(或者更好的是,获得可以由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无法处理该作业,它将把它推回到队列中并增加尝试次数。
回答如下:[首先,请注意,这是Laravel 5.3中基于数据库的队列中作业的格式。 Laravel的较新版本包含更改。
有效负载列应包含以下格式的json对象。在这种情况下,可以对作业(...\\CallQueuedHandler@call
)进行硬编码。我相信commandName键仅用于显示目的。但是,命令键是更难的部分,它应该是unserialize()支持的有效对象。看起来npm上有为此目的可用的软件包,快速搜索打开了php-serialization。
{
"job": "Illuminate\\Queue\\CallQueuedHandler@call",
"data": {
"commandName": "App\\Jobs\\MyJobClass",
"command": "O:19:\"App\\Jobs\\MyJobClass\"... /* stuff */"
}
}
您提供的json有效负载导致以下对象。作业和数据键都很重要。
{
"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
}
我想,有问题的部分是序列化的对象。重新格式化,更易于阅读(但完全破坏了它)...
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特性的事实,该特性将对模型的引用替换为包含class + identifier的简单条目,并将在__wakeup期间恢复它们。
我相信您的问题在于对json和序列化格式进行心理分析;您猜测的结构是...错误。
下一步将不会猜测任何东西。1.复制您已经拥有有效负载的确切测试通知。只需复制粘贴即可。 (您可能需要更改ID,我想它用于重复数据删除。)2.使用php-serialization构建事件数据,并旨在构建与原始事件有效内容相同的内容。完全没有变化。3.如果目前为止仍然有效,请随时更改序列化的事件数据以查看会发生什么。
从Laravel外部(NodeJS)推送到Laravel队列
我有一个作为纯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实际放入队列的内容中包含其他信息(例如时间戳,用户模型标识符等,但我认为触发该作业不是必需的。
[与php serialize()相比,数据需要在JS中进行序列化以实现类似的输出(或者更好的是,获得可以由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无法处理该作业,它将把它推回到队列中并增加尝试次数。
回答如下:[首先,请注意,这是Laravel 5.3中基于数据库的队列中作业的格式。 Laravel的较新版本包含更改。
有效负载列应包含以下格式的json对象。在这种情况下,可以对作业(...\\CallQueuedHandler@call
)进行硬编码。我相信commandName键仅用于显示目的。但是,命令键是更难的部分,它应该是unserialize()支持的有效对象。看起来npm上有为此目的可用的软件包,快速搜索打开了php-serialization。
{
"job": "Illuminate\\Queue\\CallQueuedHandler@call",
"data": {
"commandName": "App\\Jobs\\MyJobClass",
"command": "O:19:\"App\\Jobs\\MyJobClass\"... /* stuff */"
}
}
您提供的json有效负载导致以下对象。作业和数据键都很重要。
{
"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
}
我想,有问题的部分是序列化的对象。重新格式化,更易于阅读(但完全破坏了它)...
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特性的事实,该特性将对模型的引用替换为包含class + identifier的简单条目,并将在__wakeup期间恢复它们。
我相信您的问题在于对json和序列化格式进行心理分析;您猜测的结构是...错误。
下一步将不会猜测任何东西。1.复制您已经拥有有效负载的确切测试通知。只需复制粘贴即可。 (您可能需要更改ID,我想它用于重复数据删除。)2.使用php-serialization构建事件数据,并旨在构建与原始事件有效内容相同的内容。完全没有变化。3.如果目前为止仍然有效,请随时更改序列化的事件数据以查看会发生什么。