I am having a hard time figuring out what exactly is going on with my Laravel app. It's fully functional locally (Mac, php 5.5.26), so I have been testing the app out on my digital ocean droplet through forge (php 5.6.15).
I am using this package to send push notifications to the front end app which consumes my Laravel api. In order to make the api calls faster I delegated the push notifications to Laravel queues which work great locally, but I received this error when I tested on digital ocean.
[2016-01-09 20:34:09] stage.ERROR: exception 'ErrorException' with message 'Erroneous data format for unserializing 'ArrayIterator'' in {path}/{project}/vendor/laravel/framework/src/Illuminate/Queue/CallQueuedHandler.php:74
I am using the database driver. Here is the serialized job row in my local database jobs table...
{"job":"Illuminate\\Queue\\CallQueuedHandler@call","data":{"command":"O:28:\"App\\Jobs\\Push\\SendPushFollow\":4:{s:34:\"\u0000App\\Jobs\\Push\\SendPushFollow\u0000push\";O:27:\"App\\Helpers\\Push\\PushFollow\":5:{s:14:\"\u0000*\u0000ios_devices\";O:50:\"Sly\\NotificationPusher\\Collection\\DeviceCollection\":1:{s:7:\"\u0000*\u0000coll\";C:13:\"ArrayIterator\":21:{x:i:0;a:0:{};m:a:0:{}}}s:16:\"\u0000*\u0000android_count\";i:2;s:12:\"\u0000*\u0000ios_count\";i:0;s:18:\"\u0000*\u0000android_devices\";O:50:\"Sly\\NotificationPusher\\Collection\\DeviceCollection\":1:{s:7:\"\u0000*\u0000coll\";C:13:\"ArrayIterator\":953:{x:i:0;a:2:{s:162:\"APA91bGCWGMQlh6kMYVVPUjnkDKtgLmYBiHxv1WY4r3zPjmXO3C0_UcvBCoOWkiiiC8lBc4JRILBDo29K0BtGNQKKQAA46tCvJocklTp3u7_x4q8Nz9CubNuqJN_OaMRBys_HWUqNXPLzIbodjEHV_bTc-CUKurnRQ\";O:35:\"Sly\\NotificationPusher\\Model\\Device\":2:{s:42:\"\u0000Sly\\NotificationPusher\\Model\\Device\u0000token\";s:162:\"APA91bGCWGMQlh6kMYVVPUjnkDKtgLmYBiHxv1WY4r3zPjmXO3C0_UcvBCoOWkiiiC8lBc4JRILBDo29K0BtGNQKKQAA46tCvJocklTp3u7_x4q8Nz9CubNuqJN_OaMRBys_HWUqNXPLzIbodjEHV_bTc-CUKurnRQ\";s:13:\"\u0000*\u0000parameters\";a:0:{}}s:162:\"APA91bEUPnqR3t8KDhE0YTsc_HnkoxFvw4WyUpRxISm2A_2Ep7orCySVKsh2oRVSQTVOhSZS_yYjP7gup5vEnuwz2JPXcxHCc19P98E2QVNyjhTP_NvDkcfkogVIHAHpgelyGRuvm8aQ-SAs9uirxd3iBHPlZb16zA\";O:35:\"Sly\\NotificationPusher\\Model\\Device\":2:{s:42:\"\u0000Sly\\NotificationPusher\\Model\\Device\u0000token\";s:162:\"APA91bEUPnqR3t8KDhE0YTsc_HnkoxFvw4WyUpRxISm2A_2Ep7orCySVKsh2oRVSQTVOhSZS_yYjP7gup5vEnuwz2JPXcxHCc19P98E2QVNyjhTP_NvDkcfkogVIHAHpgelyGRuvm8aQ-SAs9uirxd3iBHPlZb16zA\";s:13:\"\u0000*\u0000parameters\";a:0:{}}};m:a:0:{}}}s:10:\"\u0000*\u0000message\";O:36:\"Sly\\NotificationPusher\\Model\\Message\":2:{s:42:\"\u0000Sly\\NotificationPusher\\Model\\Message\u0000text\";s:32:\"John Smith is now following you!\";s:10:\"\u0000*\u0000options\";a:12:{s:5:\"badge\";i:1;s:5:\"sound\";s:12:\"example.aiff\";s:12:\"actionLocKey\";s:20:\"Action button title!\";s:6:\"locKey\";s:13:\"localized key\";s:7:\"locArgs\";a:2:{i:0;s:14:\"localized args\";i:1;s:14:\"localized args\";}s:11:\"launchImage\";s:9:\"image.jpg\";s:5:\"title\";s:21:\"InMyBag: New Follower\";s:6:\"custom\";a:0:{}s:5:\"notId\";i:7;s:5:\"style\";s:5:\"inbox\";s:8:\"ledColor\";a:4:{i:0;i:0;i:1;i:0;i:2;i:255;i:3;i:0;}s:16:\"vibrationPattern\";a:3:{i:0;i:500;i:1;i:250;i:2;i:500;}}}}s:5:\"queue\";N;s:5:\"delay\";N;s:6:\"\u0000*\u0000job\";N;}"}}
And here's the row entry from the server table...
{"job":"Illuminate\\Queue\\CallQueuedHandler@call","data":{"command":"O:28:\"App\\Jobs\\Push\\SendPushFollow\":4:{s:34:\"\u0000App\\Jobs\\Push\\SendPushFollow\u0000push\";O:27:\"App\\Helpers\\Push\\PushFollow\":5:{s:14:\"\u0000*\u0000ios_devices\";O:50:\"Sly\\NotificationPusher\\Collection\\DeviceCollection\":1:{s:7:\"\u0000*\u0000coll\";O:13:\"ArrayIterator\":0:{}}s:16:\"\u0000*\u0000android_count\";i:2;s:12:\"\u0000*\u0000ios_count\";i:0;s:18:\"\u0000*\u0000android_devices\";O:50:\"Sly\\NotificationPusher\\Collection\\DeviceCollection\":1:{s:7:\"\u0000*\u0000coll\";O:13:\"ArrayIterator\":2:{s:162:\"APA91bGCWGMQlh6kMYVVPUjnkDKtgLmYBiHxv1WY4r3zPjmXO3C0_UcvBCoOWkiiiC8lBc4JRILBDo29K0BtGNQKKQAA46tCvJocklTp3u7_x4q8Nz9CubNuqJN_OaMRBys_HWUqNXPLzIbodjEHV_bTc-CUKurnRQ\";O:35:\"Sly\\NotificationPusher\\Model\\Device\":2:{s:42:\"\u0000Sly\\NotificationPusher\\Model\\Device\u0000token\";s:162:\"APA91bGCWGMQlh6kMYVVPUjnkDKtgLmYBiHxv1WY4r3zPjmXO3C0_UcvBCoOWkiiiC8lBc4JRILBDo29K0BtGNQKKQAA46tCvJocklTp3u7_x4q8Nz9CubNuqJN_OaMRBys_HWUqNXPLzIbodjEHV_bTc-CUKurnRQ\";s:13:\"\u0000*\u0000parameters\";a:0:{}}s:162:\"APA91bEUPnqR3t8KDhE0YTsc_HnkoxFvw4WyUpRxISm2A_2Ep7orCySVKsh2oRVSQTVOhSZS_yYjP7gup5vEnuwz2JPXcxHCc19P98E2QVNyjhTP_NvDkcfkogVIHAHpgelyGRuvm8aQ-SAs9uirxd3iBHPlZb16zA\";O:35:\"Sly\\NotificationPusher\\Model\\Device\":2:{s:42:\"\u0000Sly\\NotificationPusher\\Model\\Device\u0000token\";s:162:\"APA91bEUPnqR3t8KDhE0YTsc_HnkoxFvw4WyUpRxISm2A_2Ep7orCySVKsh2oRVSQTVOhSZS_yYjP7gup5vEnuwz2JPXcxHCc19P98E2QVNyjhTP_NvDkcfkogVIHAHpgelyGRuvm8aQ-SAs9uirxd3iBHPlZb16zA\";s:13:\"\u0000*\u0000parameters\";a:0:{}}}}s:10:\"\u0000*\u0000message\";O:36:\"Sly\\NotificationPusher\\Model\\Message\":2:{s:42:\"\u0000Sly\\NotificationPusher\\Model\\Message\u0000text\";s:32:\"John Smith is now following you!\";s:10:\"\u0000*\u0000options\";a:12:{s:5:\"badge\";i:1;s:5:\"sound\";s:12:\"example.aiff\";s:12:\"actionLocKey\";s:20:\"Action button title!\";s:6:\"locKey\";s:13:\"localized key\";s:7:\"locArgs\";a:2:{i:0;s:14:\"localized args\";i:1;s:14:\"localized args\";}s:11:\"launchImage\";s:9:\"image.jpg\";s:5:\"title\";s:21:\"InMyBag: New Follower\";s:6:\"custom\";a:0:{}s:5:\"notId\";i:10;s:5:\"style\";s:5:\"inbox\";s:8:\"ledColor\";a:4:{i:0;i:0;i:1;i:0;i:2;i:255;i:3;i:0;}s:16:\"vibrationPattern\";a:3:{i:0;i:500;i:1;i:250;i:2;i:500;}}}}s:5:\"queue\";N;s:5:\"delay\";N;s:6:\"\u0000*\u0000job\";N;}"}}
I ran an online text dif and found out that the serialized data portion of that blob has a couple of differences which occur (as the error logs pointed out) in the ArrayIterator portion. It looks like the difference is coming from the way in which the PushNotification::DeviceCollection object is serialized differs between my local machine and on the server. In my testing I hit the api endpoint locally and on the server with the same POST data to make sure that the output of the serialize should be the same but it isn't.
I am not really sure how to go about fixing this. I don't know if this is technically a bug with the PushNotification package ( I didn't see any bug reports related to this issue ) or if it's just something else I am glossing over.
Also, just on a side note, I am using another queue to send KeenIO events using a similar class structure as this Push structure and it's not having any issues whatsoever so I really feel like it's gotta be an issue with the PushNotification package somewhow...Any thoughts??
SOLVED
So it turns out it was an issue with the PHP version. My server was running 5.6 and when I made another droplet on PHP 7.0 and cloned the server, everything started working. I left the original server up and running so it could function as a queue processor for the push notifications using beanstalkd and it's working like a champ.
EDIT
I am using supervisor to run the queue:work command. I have run
php artisan queue:restart
and I've made sure that the artisan process is fully stopped when running a new test by executing a kill command via command line. Again the queue worker is having no issues with my KeenIO jobs on the server, just the PushNotification jobs.
Here's the job class:
<?php namespace App\Jobs\Push;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Bus\SelfHandling;
use Illuminate\Contracts\Queue\ShouldQueue;
use App\Jobs\SendPushEvent;
use App\Helpers\Push\PushFollow;
class SendPushFollow extends SendPushEvent implements SelfHandling, ShouldQueue {
use InteractsWithQueue, SerializesModels;
private $push;
/**
* Create a new job instance.
*
* @return void
*/
public function __construct($follower, $followee)
{
$this->push = new PushFollow($follower, $followee);
}
/**
* Execute the job.
*
* @return void
*/
public function handle(){
$this->push->send();
}
}
And here's the PushFollow class which has all of the PushNotification logic in it.
<?php namespace App\Helpers\Push;
use PushNotification;
use App\Helpers\Push\Push;
use Log;
class PushFollow extends Push {
/**
* This builds the default notification.
* @param array $data the passed in data array
* @param [type] $type android or iOS
*/
public function __construct ($follower, $followee) {
$_ios_devices = [];
$_android_devices = [];
$this->ios_count = 0;
$this->android_count = 0;
foreach($followee->devices as $_device){
if($_device->platform == "ios"){
$_ios_devices[] = PushNotification::Device($_device->identifier);
$this->ios_count++;
} elseif ($_device->platform == "android") {
$_android_devices[] = PushNotification::Device($_device->identifier);
$this->android_count++;
}
}
Log::info('FINISHED BUILDING THE LISTS!!!');
$this->ios_devices = PushNotification::DeviceCollection($_ios_devices);
$this->android_devices = PushNotification::DeviceCollection($_android_devices);
Log::info('SET THE DEVICE COLLECTIONS');
$this->message = PushNotification::Message($follower->profile->name.' is now following you!',[
'badge' => 1,
'sound' => 'example.aiff',
'actionLocKey' => 'Action button title!',
'locKey' => 'localized key',
'locArgs' => array(
'localized args',
'localized args',
),
'launchImage' => 'image.jpg',
'title' => env('APP_NAME').': New Follower',
'custom' => [],
'notId' => rand(1, 20),
'style' => 'inbox',
/*
'actions' => [
['icon' => "emailGuests", 'title' => "EMAIL GUESTS", 'callback' => "app.emailGuests"],
[ 'icon' => "snooze", 'title' => "SNOOZE", 'callback' => "app.snooze"],
],
*/
'ledColor' => [0, 0, 255, 0],
'vibrationPattern' => [500, 250, 500],
]);
Log::info('SET THE MESSAGE');
}
public function send () {
Log::info('CALLING THE SEND METHOD');
if($this->android_count) {
PushNotification::app(env('ANDROID_PUSH_NAME'))
->to($this->android_devices)
->send($this->message);
}
if($this->ios_count){
PushNotification::app(env('IOS_PUSH_NAME'))
->to($this->ios_devices)
->send($this->message);
}
}
}
And here's the Push class that all my different push classes extend.
<?php namespace App\Helpers\Push;
abstract class Push {
protected $ios_devices;
protected $android_count;
protected $ios_count;
protected $android_devices;
protected $message;
}
Oh and here's the stack trace as well.
#0 [internal function]: Illuminate\Foundation\Bootstrap\HandleExceptions->handleError(2, 'Erroneous data ...', '/home/forge/def...', 74, Array)
#1 {path_to_project}/vendor/laravel/framework/src/Illuminate/Queue/CallQueuedHandler.php(74): unserialize('O:28:"App\\Jobs\\...')
#2 {path_to_project}/vendor/laravel/framework/src/Illuminate/Queue/Jobs/Job.php(212): Illuminate\Queue\CallQueuedHandler->failed(Array)
#3 {path_to_project}/vendor/laravel/framework/src/Illuminate/Queue/Worker.php(261): Illuminate\Queue\Jobs\Job->failed()
#4 {path_to_project}/vendor/laravel/framework/src/Illuminate/Queue/Worker.php(201): Illuminate\Queue\Worker->logFailedJob('database', Object(Illuminate\Queue\Jobs\DatabaseJob))
#5 {path_to_project}/vendor/laravel/framework/src/Illuminate/Queue/Worker.php(159): Illuminate\Queue\Worker->process('database', Object(Illuminate\Queue\Jobs\DatabaseJob), '5', 0)
#6 {path_to_project}/vendor/laravel/framework/src/Illuminate/Queue/Worker.php(111): Illuminate\Queue\Worker->pop(NULL, 'keen,push_notif...', 0, 3, '5')
#7 {path_to_project}/vendor/laravel/framework/src/Illuminate/Queue/Worker.php(87): Illuminate\Queue\Worker->runNextJobForDaemon(NULL, 'keen,push_notif...', 0, 3, '5')
#8 {path_to_project}/vendor/laravel/framework/src/Illuminate/Queue/Console/WorkCommand.php(103): Illuminate\Queue\Worker->daemon(NULL, 'keen,push_notif...', 0, 128, 3, '5')
#9 {path_to_project}/vendor/laravel/framework/src/Illuminate/Queue/Console/WorkCommand.php(71): Illuminate\Queue\Console\WorkCommand->runWorker(NULL, 'keen,push_notif...', 0, 128, true)
#10 [internal function]: Illuminate\Queue\Console\WorkCommand->fire()
#11 {path_to_project}/vendor/laravel/framework/src/Illuminate/Container/Container.php(507): call_user_func_array(Array, Array)
#12 {path_to_project}/vendor/laravel/framework/src/Illuminate/Console/Command.php(150): Illuminate\Container\Container->call(Array)
#13 {path_to_project}/vendor/symfony/console/Command/Command.php(256): Illuminate\Console\Command->execute(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#14 {path_to_project}/vendor/laravel/framework/src/Illuminate/Console/Command.php(136): Symfony\Component\Console\Command\Command->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#15 {path_to_project}/vendor/symfony/console/Application.php(837): Illuminate\Console\Command->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#16 {path_to_project}/vendor/symfony/console/Application.php(189): Symfony\Component\Console\Application->doRunCommand(Object(Illuminate\Queue\Console\WorkCommand), Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#17 {path_to_project}/vendor/symfony/console/Application.php(120): Symfony\Component\Console\Application->doRun(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#18 {path_to_project}/vendor/laravel/framework/src/Illuminate/Foundation/Console/Kernel.php(107): Symfony\Component\Console\Application->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#19 {path_to_project}/artisan(36): Illuminate\Foundation\Console\Kernel->handle(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#20 {main}
You can even retry all jobs at once by executing the php artisan queue:retry --all command. Alternatively, if you want to retry failed jobs from a certain queue, you can execute the php artisan queue:retry --queue=high-priority command.
Laravel queues provide a unified API across a variety of different queue backends, such as Beanstalk, Amazon SQS, Redis, or even a relational database. Queues allow you to defer the processing of a time consuming task, such as sending an email, until a later time.
So it turns out it was an issue with the PHP version. My server was running 5.6 and when I made another droplet on PHP 7.0 and cloned the server, everything started working. I left the original server up and running so it could function as a queue processor for the push notifications using beanstalkd and it's working like a champ.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With