Error while sending stmt prepare packet

Laravel Version: Laravel Framework Lumen (5.8.8) (Laravel Components 5.8.*) PHP Version: PHP 7.2.19-0ubuntu0.18.04.1 Database Driver & Version: mysql Ver 14.14 Distrib 5.7.26 Description: Queue...

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and
privacy statement. We’ll occasionally send you account related emails.

Already on GitHub?
Sign in
to your account


Closed

mrahmadt opened this issue

Jun 22, 2019

· 61 comments

Comments

@mrahmadt

  • Laravel Version: Laravel Framework Lumen (5.8.8) (Laravel Components 5.8.*)
  • PHP Version: PHP 7.2.19-0ubuntu0.18.04.1
  • Database Driver & Version: mysql Ver 14.14 Distrib 5.7.26

Description:

Queue jobs is losing connection to database and throw exception
ErrorException: Warning: Error while sending STMT_PREPARE packet

Queue command (managed by supervisord) artisan queue:work —queue=children —sleep=3 —tries=3 —daemon

The error is not related to large data sent to database, it seems to be it’s related to some how data connection is lost with database

My error comes from a simple query
$child = Child::find($child_id);

Let me know if you need any further information

PS: No change in mysql nor php default settings.

Steps To Reproduce:

Sometime below steps will work
1- Make sure queue is running
2- Restart database (/etc/init.d/mysql restart)
3- Send a job to the queue
4- You will get this error
5- Send another job to the queue (no error)

@mrahmadt

Small clarification, my job will just call a model that will process the data

<?php
namespace AppJobs;
use IlluminateSupportFacadesDB;
use AppModelsChild;

class childjob extends Job {
    public $tries = 3;
    public $timeout = 1800;
    public $child_id;
    public function __construct($child_id)
    {
        $this->child_id = $child_id;
    }
    public function handle(){
        Child::setsomething($this->child_id);
        return true;
    }
}

and inside Child Model:

public static function setsomething($child_id){
    $child = Child::find($child_id);
}

@driesvints

Hey there,

Can you first please try one of the support channels below? If you can actually identify this as a bug, feel free to report back and I’ll gladly help you out and re-open this issue.

  • Laracasts Forums
  • Laravel.io Forums
  • StackOverflow
  • Discord
  • Larachat
  • IRC

Also: please post this on the Lumen repo if you decide to repost. Thanks!

Thanks!

@decowboy

@mrahmadt

@koenhoeijmakers

Could this be because the database service is getting a new PID for whatever reason and that the old one is still loaded since horizon is a long running process?

@fridzema

Since i have updated my application i also get this error regularly.
Code has been changed by over 400 commits, find the culprit in this is not really easy.
Only big thing changed on the server is from mysql -> mariadb.

@koenhoeijmakers

Our problem indeed also happens on MariaDB, not sure about mysql.

@driesvints

I’ll re-open this to have a look at a later time. Feel free to provide more info on the matter in the meantime.

@fridzema

What is can see so far:
Happens on different random jobs.
Happens around 1 of 1000 jobs, could be complete random.

Examples:

ErrorException[internal] in unserialize warning
Warning: Error while sending STMT_PREPARE packet. PID=26143


variable_representation | O:28:"AppJobsFetchProofscopeData":8:{s:15:"*project_file";O:45:"IlluminateContractsDatabaseModelIdentifier":4:{s:5:"class";s:15:"AppProjectFile";s:2:"id";i:154404;s:9:"relations";a:1:{i:0;s:7:"Project";}s:10:"connection";N;}s:6:"*job";N;s:10:"connection";N;s:5:"queue";s:13:"project-files";s:15:"chainConnection";N;s:10:"chainQueue";N;s:5:"delay";N;s:7:"chained";a:2:{i:0;s:367:"O:34:"AppJobsFetchProjectFileThumbnail":8:{s:15:"*project_file";O:45:"IlluminateContractsDatabaseModelIdentifier":4:{s:5:"class";s:15:"AppProjectFile";s:2:"id";i:154404;s:9:"relations";a:1:{i:0;s:7:"Project";}s:10:"connection";N;}s:6:"*job";N;s:10:"connection";N;s:5:"queue";N;s:15:"chainConnection";N;s:10:"chainQueue";N;s:5:"delay";N;s:7:"chained";a:0:{}}";i:1;s:364:"O:31:"AppJobsForceRenderProjectFile":8:{s:15:"*project_file";O:45:"IlluminateContractsDatabaseModelIdentifier":4:{s:5:"class";s:15:"AppProjectFile";s:2:"id";i:154404;s:9:"relations";a:1:{i:0;s:7:"Project";}s:10:"connection";N;}s:6:"*job";N;s:10:
-- | --
ErrorException/app/Jobs/InsertSystemLog.php in AppJobsInsertSystemLog::handle warning
Warning: Error while sending STMT_PREPARE packet. PID=26147


/app/Jobs/InsertSystemLog.php in AppJobsInsertSystemLog::handle at line 100
        $log->save();
    }
}

@mrahmadt

@mrahmadt

Since i have updated my application i also get this error regularly.
Code has been changed by over 400 commits, find the culprit in this is not really easy.
Only big thing changed on the server is from mysql -> mariadb.

Same here, I started to get this error after lumen upgrade

@fridzema

Some jobs will also be marked as failed in horizon, most of them go trough.

@Christophvh

Getting the same issue. Never had this issue on Laravel 5.6 but after updating to 5.7 this now happens daily. It looks like jobs are not actually failing since I have no items in the failed_jobs table, yet Sentry reports 80 issues. We are working with MySQL so not mariadb related

All these issues seem to be related:

  • PDO::prepare(): MySQL server has gone away
  • E_WARNING: Error while sending STMT_PREPARE packet. PID=10

@michaelnguyen2021

I have the exact same error on Laravel 5.8 with Mysql 5.6 and I thought it has to do with Telescope or horizon, but apparently, it is more common than I thought.

@jlmmns

@drbyte

Adding mine for context:
Laravel 5.8.28
mysql Ver 15.1 Distrib 10.2.25-MariaDB and 10.1.36-MariaDB
Happens with and without telescope installed.

I’m seeing both the STMT_PREPARE and MySQL server has gone away errors.

@driesvints

Seems like this PR probably causes this but it’s actually quite logic. If you’re in a transaction and lose connection, there’s no recovery from that.

Are all of you using transactions?

@fridzema

@driesvints In my case i just use Model::create()
Seems a change that was already in 5.1 i think it started happening for me between 5.7/5.8 reverted a couple version but doesn’t seem to fix it. I think it is somewhere in a horizon update.

@mrahmadt

I’m not using any transaction

I doubt this error related to losing connection, i have my code hosted with
my database and no errors in MySQL logs

This error is very random for me, in one day I get like 10 errors, next few
day no error at all

PS: my app is not production so it’s used only by me (server not overloaded)

On Fri, Jul 12, 2019 at 17:01 Dries Vints ***@***.***> wrote:
Seems like this PR <#12929>
probably causes this but it’s actually quite logic. If you’re in a
transaction and lose connection, there’s no recovery from that.

Are all of you using transactions?


You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
<#28920?email_source=notifications&email_token=AAHJ3YNVJRGYVQ4QOMXG3OLP7CFDNA5CNFSM4H2XQDTKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGODZZ2ZCQ#issuecomment-510897290>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAHJ3YPGHQGOWTDRNBOO5QLP7CFDNANCNFSM4H2XQDTA>
.


echo «Hello World :)»

@jlmmns

@driesvints No transactions.

It seems it has to do with Horizon/Telescope.
Although Telescope is fully disabled.

Below you can find some of our Sentry logs:

Screen Shot 2019-07-12 at 9 35 07 AM

Screen Shot 2019-07-12 at 9 34 16 AM

Our telescope_monitoring table is completely empty, too, so it shouldn’t have to do with that select query.

@Christophvh

@driesvints 3 separate listeners are failing in our application and none of them have database-transactions. It might indeed be a horizon update, we started to notice it after a composer update. We don’t use telescope so horizon seems most likely.

@mrahmadt

@koenhoeijmakers

I do not use telescope so i don’t think the problem lies there, no transactions too

@LaVolsi

I too am facing this issue. I am not using horizon or telescope. I do not have any jobs that are shown as failed in my DB but I do get the notifications a few times a day. It fails randomly on any job in the program. I have very little traffic on the server. I have been trying to figure it out for the past few days now.

I only receive the «Error while sending STMT_PREPARE packet. PID=*»
I have not received the «MYSQL server has gone away.»

Laravel 5.8.28
MYSQL version: 5.7.26

Screenshot from 2019-07-12 14-28-05

The server is deployed using forge. My worker settings:
connection = redis
queue = default
timeout = 0
processes = 1
tries = 3

I am going to bump up the processes number and see if that helps and then I’ll report back

@LaVolsi

@sebestenyb I think we are all using sentry. Sounds like we know where the problem lies now. I guess we should notify sentry next?

@drbyte

So the question remains: do we all use Sentry?

I do use Sentry. And I don’t recall seeing the issue reported in HoneyBadger, which I also use.

@fridzema

I am using "sentry/sentry-laravel": "1.1.0", but at the time of updating all packages is also updated this, and wonder if the cause is in this package version. @sebestenyb Are you also receiving this errors 1.0.0?

@ppelgrims

I’m with @Christophvh on the question about Sentry.

The error itself is pretty normal for long running jobs, but it supposed to be caught by the framework and transformed to a QueryException (which in turn triggers the re-connection to the database), so it should never reach Sentry in its native form.
But it does. (Maybe even before the framework catches and handles it? That would explain why there’s no failed jobs)

So the question remains: do we all use Sentry?

I do: "sentry/sentry-laravel": "^1.0.0",
And also updated it to 1.0 the same time we did the 5.8 update.

Perhaps parent::report($exception); should be placed at the beginning of the report method, rather than at the end of it? I don’t see the error appear in my logs either.

@drbyte

my composer.json:
"sentry/sentry-laravel": "^1.0",

and composer show | grep sentry:

sentry/sdk             2.0.3      This is a metapackage shipping sentry/sentry wit...
sentry/sentry          2.1.1      A PHP SDK for Sentry (http://sentry.io)
sentry/sentry-laravel  1.1.0      Laravel SDK for Sentry (https://sentry.io)

@CharlieEtienne

So the question remains: do we all use Sentry?

It may come from Sentry: On a project, I’m using both Sentry and Bugsnag, but this error only appears in Sentry.

NB: It happened both in Sentry 1.0.2 and 1.1.0

@markdza

Happening to our app too. It’s happening in a queued job and am using this sentry

sentry/sdk             2.0.3      This is a metapackage shipping sentry/sentry wit...
sentry/sentry          2.1.1      A PHP SDK for Sentry (http://sentry.io)
sentry/sentry-laravel  1.1.0      Laravel SDK for Sentry (https://sentry.io)

Along with Laravel Framework 5.8.27

No issues in Laravel 5.7.

Anyone know a workaround?

@oleksiyPetlyuk

Same issue on our app. We are using queued jobs and sentry

sentry/sdk             2.0.3      This is a metapackage shipping sentry/sentry wit...
sentry/sentry          2.1.1      A PHP SDK for Sentry (http://sentry.io)
sentry/sentry-laravel  1.0.1      Laravel SDK for Sentry (https://sentry.io)

Laravel Framework 5.8.28

@koenhoeijmakers

As replied by a dev from Sentry in the sentry-laravel issue

Interesting. We would have to dig where the warning is emitted from since it might not be silenced and thus will be caught by Sentry which is correct.

Since 2.x of the base SDK (and 1.x of Laravel) «errors» (like warnings and notices) are captured much better which might be the reason of the uptick of the errors. We also now capture every «error» by default which you can change using the error_types option.

To reiterate what is said in the other issues, this is a warning and Laravel recovers from this gracefully so it’s mere informational that this warning is emitted, it does not crash your apps or jobs these warnings were always emitted but not always captured.

@decowboy

For reference:

Our problem indeed also happens on MariaDB, not sure about mysql.

I’m experiencing the issue on MySQL.

Happens around 1 of 1000 jobs, could be complete random.

Same for me.

I’m using https://github.com/GeneaLabs/laravel-model-caching to cache my queries

I’m not using any form of model caching

It seems it has to do with Horizon/Telescope.

I’m also using Horizon but not Telescope.

Are all of you using transactions?

No transactions in my jobs either.

It seems like everybody with this problem is using Sentry?

I’m also using Sentry.

@koenhoeijmakers

The warnings seem to have stopped for me after I’ve changed my retry_after and timeout according to the docs

The --timeout value should always be at least several seconds shorter than your retry_after configuration value. This will ensure that a worker processing a given job is always killed before the job is retried. If your --timeout option is longer than your retry_after configuration value, your jobs may be processed twice.

My timeout was 600 seconds in horizon but the retry_after was still the same (in the config/queue.php it’s set at 90), changing the retry_after to 630 seconds fixed it :)

@driesvints

I’m going to close this as this seems to be Sentry specific and there really isn’t an issue except from the warning. Thanks to everyone who helped investigate this 👍

@decowboy

My apologies if it is frowned upon to comment on a closed issue, but I’d like to quickly reply to the solution suggested by @koenhoeijmakers

The warnings seem to have stopped for me after I’ve changed my retry_after and timeout according to the docs

My configuration already had the retry_after set significantly higher than the timeout before this issue starting popping up, so (at least in my case) the two are not related.

@markdza

Anyone have a solution for this? It’s still an issue to at least v5.8.32

@Mult1Hunter

@fridzema

@Mult1Hunter

Thanks. Looks like we are stuck with this warning in sentry then. Don’t want to silence all warnings.

@Mult1Hunter

I ended up adding this method to Exceptions/Handler.php:

public function shouldReport(Exception $e)
    {
        // check if sentry is trying to falsely report 'Warning: Error while sending STMT_PREPARE packet. PID=XX'
        if (strpos($e->getMessage(), 'STMT_PREPARE packet') !== 'false') {
            return parent::shouldReport($e);
        }
    }```

@mrahmadt

I ended up adding this method to Exceptions/Handler.php:

public function shouldReport(Exception $e)
    {
        // check if sentry is trying to falsely report 'Warning: Error while sending STMT_PREPARE packet. PID=XX'
        if (strpos($e->getMessage(), 'STMT_PREPARE packet') !== 'false') {
            return parent::shouldReport($e);
        }
    }```
public function shouldReport(Exception $e)
{
        // check if sentry is trying to falsely report 'Warning: Error while sending STMT_PREPARE packet. PID=XX'
        if (strpos($e->getMessage(), 'STMT_PREPARE packet') === false) {
            return parent::shouldReport($e);
        }
}

@infostreams

@mrahmadt What happens if the error message does NOT contain ‘STMT_PREPARE packet’?

In your case it’s undefined / not explicit, so I rewrote your code as follows:

    public function shouldReport(Exception $e)
    {
        // check if sentry is trying to falsely report 'Warning: Error while sending STMT_PREPARE packet. PID=XX'
        // see https://github.com/laravel/framework/issues/28920
        if (strpos($e->getMessage(), 'STMT_PREPARE packet') !== false) {
            return false;
        }

        return parent::shouldReport($e);
    }

@nachete1987

I continue obtaining the error even though apply the code from last comment

@gpn273

I continue obtaining the error even though apply the code from last comment

I assume the Laravel logger is capturing it and logging it as opposed to the Exception Handler.

@EvilTwin01

I also have the same issue.

Laravel 6.5.0
No sentry used.
More > 1000 Jobs
Queue limit to 1 process.
Horizon timeout set to 3600.

ErrorException: Error while sending STMT_PREPARE packet. PID=25026 /home/forge/ggwp/vendor/laravel/framework/src/Illuminate/Database/Connection.php:327

@jilenloa

Our problem indeed also happens on MariaDB, not sure about mysql.

It happens on mysql too

@miholeus

so the best solution is to discard error in handler?

@mfn
mfn

mentioned this issue

Mar 30, 2020

@Qraxin

I had the same problem with my laravel v6.18.0.
And the error stopped coming after update sentry/sentry-laravel library from v1.5.0 to v1.8.0 by command composer update sentry/sentry-laravel.

I continue obtaining the error even though apply the code from last comment

It also should help here, if the decision from comment above (excluding error by Error Handler) doesn’t work.

Sometimes programmers have to maintain and support legacy projects written in older versions of frameworks.

So do I. One of my projects still uses Laravel 4 and, unfortunately, there’s a bug in its Database package which sometimes causes an error when working with long running jobs.

The reason

Laravel 4 tries to automatically reconnect to MySQL when connection is lost (e.g. after being idle for more than MySQL’s wait_timeout) and here’s how:

/**
 * Determine if the given exception was caused by a lost connection.
 *
 * @param  IlluminateDatabaseQueryException
 * @return bool
 */
protected function causedByLostConnection(QueryException $e)
{
    return str_contains($e->getPrevious()->getMessage(), 'server has gone away');
}

Unfortunately, ‘server has gone away’ is not the only error message signaling that the database connection is lost and that’s why sometimes Laravel fails to reconnect when it’s necessary.

This bug has already been fixed in Laravel 5.x, so let’s see how it handles the same task:

/**
 * Determine if the given exception was caused by a lost connection.
 *
 * @param  Exception  $e
 * @return bool
 */
protected function causedByLostConnection(Exception $e)
{
    $message = $e->getMessage();

    return Str::contains($message, [
        'server has gone away',
        'no connection to the server',
        'Lost connection',
        'is dead or not enabled',
        'Error while sending',
        'decryption failed or bad record mac',
        'SSL connection has been closed unexpectedly',
    ]);
}

Okay, now let’s fix this in Laravel 4 without changing the code of the framework (it’s surprisingly hard).

The solution

To fix the problem, we have to perform the following steps:

1) Override the IlluminateDatabaseMySqlConnection class and fix the causedByLostConnection method

2) Override the IlluminateDatabaseConnectorsConnectionFactory class, so it uses the fixed version of MySqlConnection class

3) Override the DatabaseServiceProvider, so Laravel uses the overridden ConnectionFactory class

Ok, let’s do it.

First of all, create the following class:

<?php

namespace YourAppServicesIlluminateDatabase;

use IlluminateDatabaseQueryException;
use IlluminateSupportStr;

class MySqlConnection extends IlluminateDatabaseMySqlConnection
{
    /**
     * Determine if the given exception was caused by a lost connection.
     *
     * @param  IlluminateDatabaseQueryException
     * @return bool
     */
    protected function causedByLostConnection(QueryException $e)
    {
        $message = $e->getMessage();

        return Str::contains(
            $message,
            [
                'server has gone away',
                'no connection to the server',
                'Lost connection',
                'is dead or not enabled',
                'Error while sending',
                'decryption failed or bad record mac',
                'SSL connection has been closed unexpectedly',
            ]
        );
    }
}

As you see, in this class we just replace causedByLostConnection method of Laravel 4 with the one from Laravel 5.x.

Now we have to make the framework use this new class instead of a stock one.

For this purpose we have to override the ConnectionFactory class as follows:

<?php

namespace YourAppServicesIlluminateDatabaseConnectors;

use YourAppServicesIlluminateDatabaseMySqlConnection;
use IlluminateDatabasePostgresConnection;
use IlluminateDatabaseSQLiteConnection;
use IlluminateDatabaseSqlServerConnection;
use PDO;

class ConnectionFactory extends IlluminateDatabaseConnectorsConnectionFactory
{
    /**
     * Create a new connection instance.
     *
     * @param  string $driver
     * @param  PDO   $connection
     * @param  string $database
     * @param  string $prefix
     * @param  array  $config
     * @return IlluminateDatabaseConnection
     *
     * @throws InvalidArgumentException
     */
    protected function createConnection($driver, PDO $connection, $database, $prefix = '', array $config = [])
    {
        if ($this->container->bound($key = "db.connection.{$driver}")) {
            return $this->container->make($key, [$connection, $database, $prefix, $config]);
        }

        switch ($driver) {
            case 'mysql':
                return new MySqlConnection($connection, $database, $prefix, $config);

            case 'pgsql':
                return new PostgresConnection($connection, $database, $prefix, $config);

            case 'sqlite':
                return new SQLiteConnection($connection, $database, $prefix, $config);

            case 'sqlsrv':
                return new SqlServerConnection($connection, $database, $prefix, $config);
        }

        throw new InvalidArgumentException("Unsupported driver [$driver]");
    }
}

And now we have to make sure that Laravel uses our overridden ConnectionFactory, so we have to extend its DatabaseServiceProvider as follows:

<?php

namespace YourAppServiceProviders;

use YourAppServicesIlluminateDatabaseConnectorsConnectionFactory;
use IlluminateDatabaseDatabaseManager;

class DatabaseServiceProvider extends IlluminateDatabaseDatabaseServiceProvider
{
    /**
     * Register the service provider.
     *
     * @return void
     */
    public function register()
    {
        $this->app->bindShared('db.factory', function($app)
        {
            return new ConnectionFactory($app);
        });

        $this->app->bindShared('db', function($app)
        {
            return new DatabaseManager($app, $app['db.factory']);
        });
    }
}

Finally, replace the stock DatabaseServiceProvider with your version in the app/config/app.php file:

'providers' => [
    ...
    //'IlluminateDatabaseDatabaseServiceProvider',
    'YourAppServiceProvidersDatabaseServiceProvider',
    ...
];

That’s it!

Now Laravel 4 will be able to identify all possible situations when a database connection is lost and it will automatically reconnect instead of throwing a strange exception.

← Back

РЕДАКТИРОВАТЬ: Добавление DB :: connection () -> reconnect (); метод отправки после получения электронных писем из сеанса, устраняет проблему. Похоже, что БД отключается или слишком много подключений или что-то в этом роде.

Я считаю, что у меня есть проблема с отключением MySQL на производственном сервере. Сервер соответствует моей локальной настройке dev (используя Homestead 2) и является Ubuntu, MySQL, Nginx и PHP-FPM.

Я использую Laravel 4.2 и создал функциональные возможности для взаимодействия с кампанией Mailchimp, создания статического сегмента и добавления электронных писем на основе отфильтрованных критериев в этот сегмент для отправки электронной почты.

Первоначально я запускал метод whereIn () для модели, чтобы получить коллекцию контактов, которые соответствовали массиву электронных писем, примерно 2600 электронных писем было передано whereIn () в качестве значения.

На моем рабочем сервере я продолжал получать сообщение об ошибке (безупречно работает при локальной настройке dev):

Error while sending STMT_PREPARE packet. PID=20615

Итак, во время моего исследования я обнаружил, что это может быть связано с max_allowed_packet в конфигурации MySQL сервера, поэтому я изменил my.cnf и увеличил значение до 256M (на моей локальной машине разработчика значение 16M и достаточно). Это не повлияло на ошибку.

Я решил пойти дальше, и вместо того, чтобы использовать whereIn (), в качестве теста создайте новую коллекцию, добавляя каждый контакт один за другим, но, к сожалению, я все еще получаю ту же ошибку, даже при использовании одного электронного письма. Это запрос, который не выполняется в этом случае:

select * from `contacts` where `contacts`.`deleted_at` is null and `email` = joebloggs@example.com limit 1

Так что это явно указывает на какую-то неверную конфигурацию на моем производственном сервере, хотя я убедился, что и моя локальная среда, и производственные конфигурации MySQL точно совпадают.

Итак, в общем, моя локальная среда работает нормально и выполняет код без проблем, но рабочий сервер возвращает ошибку пакета.

Я сейчас немного растерялся, как поступить. Кто-нибудь может помочь, пожалуйста?

Вот код, который я использую для получения записей:

// send() method to filter results based on a set of search fields, probably should rename this to filter

public function send($id)
{
$campaign = $this->getSavedCampaign($id);
$haveAttended = explode(',', Input::get('have_attended'));
$haveNotAttended = explode(',', Input::get('have_not_attended'));
$account = explode(',', Input::get('account'));
$companyName = explode(',', Input::get('company_name'));
$industryType = explode(',', Input::get('industry_type'));
$accountManager = explode(',', Input::get('account_manager'));
$jobTitle = explode(',', Input::get('job_title'));
$contactEmail = explode(',', Input::get('contact_email'));

// Check if there has been a POST request and if so get the filtered contact emails and add them to the session
if (Request::method() == 'POST')
{
// Retrieve an array of contact emails based on the filters supplied
$contactEmails = $this->contact->getContactEmails($haveAttended, $haveNotAttended, $account, $companyName, $industryType, $accountManager, $jobTitle, $contactEmail)->lists('email');

// Create a new Mailchimp static segment and return its ID
$segmentId = $this->createNewSegment(MailchimpWrapper::lists()->staticSegments('123456789'), $id);

// Add the emails array generated above to the static segment in Mailchimp
$this->addContactEmailsToSegment($contactEmails, $segmentId);

// Retrieve all the emails that matched a subscriber in Mailchimp that were added to the static segment
$emails = $this->getSegmentEmails(Config::get('mailchimp::apikey'), '123456789', 'subscribed', $segmentId);

// Put the emails array and the segment id in to the session
Session::put('emails', $emails);
Session::put('segmentId', $segmentId);
}

// Check if the session contains an array of emails and if so retrieve them and pull back an eloquent collection of contacts that match the emails stored in the session
if (Session::get('emails'))
{
$emails = Session::get('emails');

// EDIT: If I add DB::connection()->reconnect(); here this allieviates the issue

$contacts = $this->contact->getContactEmails($haveAttended, $haveNotAttended, $account, $companyName, $industryType, $accountManager, $jobTitle, $contactEmail, $emails)->paginate(10)->appends([
'have_attended'     => Input::get('have_attended'),
'have_not_attended' => Input::get('have_not_attended'),
'account'           => Input::get('account'),
'industry_type'     => Input::get('industry_type'),
'account_manager'   => Input::get('account_manager'),
'job_title'         => Input::get('job_title'),
'contact_email'     => Input::get('contact_email')
]);
}

$this->layout->content = View::make('admin.newsletters.send', compact('campaign', 'contacts'))->withErrors($this->errors);
}

Вот как я получаю кампанию Mailchimp:

// getSavedCampaign() method which retrieves the Mailchimp campaign we will be attaching the filtered segment to

public function getSavedCampaign($id)
{
$campaign = (object) MailchimpWrapper::campaigns()->getList(['campaign_id' => $id], 0, 1)['data'][0];
$campaign->create_time = new Carbon($campaign->create_time);
$campaign->send_time = new Carbon($campaign->send_time);
$campaign->content_updated_time = new Carbon($campaign->content_updated_time);

return $campaign;
}

Вот как я получаю контакты / электронные письма из таблицы контактов на основе отфильтрованных результатов:

public function scopeGetContactEmails($query, $haveAttended, $haveNotAttended, $account, $companyName, $industryType, $accountManager, $jobTitle, $contactEmail, $emails = null)
{
// If the emails session variable exists (is not null) simply run a whereIn query on the contacts table to retrieve all contacts that match an email in the array, otherwise run the filters
if ( ! is_null($emails))
{
$query->whereIn('email', $emails);
}
else
{
$query->orderBy('email', 'asc')
->where('contactable', 0)
->where('opt_out', 0)
->where('email', '!=', DB::raw("concat('', email * 1)"));

if ( ! empty($companyName[0]))
{
$query->whereHas('account', function($query) use ($companyName)
{
$query->where('company_name', 'like', "%$companyName[0]%");
});
}

if ( ! empty($account[0]))
{
$query->whereHas('account', function($query) use ($account)
{
$query->whereIn('id', $account);
});
}

if ( ! empty($accountManager[0]))
{
$query->whereHas('account', function($query) use ($accountManager)
{
$query->whereHas('user', function($query) use ($accountManager)
{
$query->whereIn('id', $accountManager);
});
});
}

if ( ! empty($industryType[0]))
{
$query->whereHas('account', function($query) use ($industryType)
{
$query->whereHas('industryType', function($query) use ($industryType)
{
$query->whereIn('id', $industryType);
});
});
}

if ( ! empty($haveAttended[0]) or ! empty($haveNotAttended[0]))
{
$query->join('delegates', 'contacts.id', '=', 'delegates.contact_id')
->join('delegate_event', 'delegates.id', '=', 'delegate_event.delegate_id')
->join('events', 'delegate_event.event_id', '=', 'events.id')
->join('courses', 'events.course_id', '=', 'courses.id');
}

if ( ! empty($haveAttended[0]))
{
$query->whereIn('courses.id', $haveAttended);
}

if ( ! empty($haveNotAttended[0]))
{
$query->whereNotIn('courses.id', $haveNotAttended);
}

if ( ! empty($jobTitle[0]))
{
$query->whereIn('contacts.job_title_id', $jobTitle);
}

if ( ! empty($contactEmail[0]))
{
$query->whereIn('contacts.id', $contactEmail);
}
}
}

Вот как я создаю новый сегмент Mailchimp:

public function createNewSegment($segments, $campaignId)
{
foreach ($segments as $key => $segment)
{
if ($segment['name'] == 'CREAM-' . $campaignId)
{
MailchimpWrapper::lists()->staticSegmentDel('123456789', $segment['id']);
}
}

$segment = MailchimpWrapper::lists()->staticSegmentAdd('123456789', 'CREAM-' . $campaignId);

return $segment['id'];
}

Вот как я добавляю электронные письма, полученные в созданный сегмент:

public function addContactEmailsToSegment($contactEmails, $segmentId)
{
$listEmails = $this->generateListEmails(Config::get('mailchimp::apikey'), '123456789', 'subscribed');

$emails = $this->buildSegmentEmails($contactEmails, $listEmails);

if ($emails)
{
$emailsChunk = array_chunk($emails, 1000);

foreach ($emailsChunk as $emails)
{
MailchimpWrapper::lists()->staticSegmentMembersAdd('123456789', $segmentId, $emails);
}
}
}

Это функция, которая извлекает все электронные письма / контакты, которые соответствуют подписчикам в Mailchimp и были добавлены в сегмент:

public function getSegmentEmails($apiKey, $listId, $status, $segmentId)
{
$conditions = '&segment[saved_segment_id]=' . $segmentId;

return $this->generateListEmails($apiKey, $listId, $status, $conditions);
}

Вот как списочные письма извлекаются из Mailchimp:

public function generateListEmails($apiKey, $listId, $status, $conditions = null)
{
$url = 'http://us5.api.mailchimp.com/export/1.0/list?apikey=' . $apiKey . '&id=' . $listId . '&status=' . $status;

if ( ! is_null($conditions))
{
$url .= '&segement[match]=all' . $conditions;
}

$handle = @fopen($url, 'r');
$chunk_size = 4096;
$i = 0;
$header = [];

while ( ! feof($handle))
{
$buffer = fgets($handle, $chunk_size);

if (trim($buffer) != '')
{
$obj = json_decode($buffer);
$listEmails[$obj[0]] = $obj[0];
$i++;
}
}

fclose($handle);

unset($listEmails['Email Address']);

return $listEmails;
}

2

Задача ещё не решена.

Понравилась статья? Поделить с друзьями:
  • Error while running apache2ctl graceful httpd not running trying to start
  • Error while replacing a missing file insufficient permission to access the file
  • Error while reading xml file
  • Error while reading mysql settings file bind error code 9
  • Error while reading movie unity