Skip to content
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

Guzzle rewind_body() called with null Argument #246

Closed
Code-Working opened this issue Feb 22, 2017 · 22 comments
Closed

Guzzle rewind_body() called with null Argument #246

Code-Working opened this issue Feb 22, 2017 · 22 comments
Assignees

Comments

@Code-Working
Copy link

From time to time I get the following exception:
Exception: Argument 1 passed to GuzzleHttp\Psr7\rewind_body() must implement interface Psr\Http\Message\MessageInterface, null given, called in /path-to-my-app/vendor/googleads/googleads-php-lib/src/Google/AdsApi/Common/GuzzleLogMessageHandler.php on line 74 in [/srv/vhosts/com.ppcrocket.dashboard/app_dev/vendor/guzzlehttp/psr7/src/functions.php, line 274]

I can't reproduce why I'm getting this error, but setting $response = null in GuzzleLogMessageHandler.php, line 58-62 seems to be not so good idea since the rewind_body() function of Guzzle expects a MessageInterface and not null.

Anyway, when I set the log level of all loggers to debug, the log message that comes immediately before the exception is the following:
[2017-02-22 15:06:59] AW_REPORT_DOWNLOADER.WARNING: my.server.com GuzzleHttp/6.2.1 curl/7.47.0 PHP/7.0.13-0ubuntu0.16.04.1 - [22/Feb/2017:15:06:59 +0000] "POST /api/adwords/reportdownload/v201609 HTTP/1.1" NULL NULL

An "normal" log message would look like this:
[2017-02-22 15:05:32] AW_REPORT_DOWNLOADER.INFO: my.server.com GuzzleHttp/6.2.1 curl/7.47.0 PHP/7.0.13-0ubuntu0.16.04.1 - [22/Feb/2017:15:05:32 +0000] "POST /api/adwords/reportdownload/v201609 HTTP/1.1" 200 33836193

I'm just guessing that either the AdWords server takes too long to respond or does not respond at all.

Regards
Code-Working

@Code-Working
Copy link
Author

Code-Working commented Feb 23, 2017

I made some more investigations to check where this error comes from:
It seems as if the requested report files are sometimes too big.

We are downloading lots of KEYWORDS_PERFORMANCE_REPORTs segmented by metrics and device.
The download format is CSV_GZ.

From the 20 biggest files, only 18 could be downloaded with the new API, while it works well with the old API.

A critical size seems to be more than 33MB.
However, two reports with 65MB and 55 MB (still csv.gz) could be downloaded.

@fiboknacky
Copy link
Member

Hello @Code-Working

Thank you for informing this!

Could you please share your full report definition or SOAP logs of the reports that have this problem to adwordsapiadvisor@google.com?
From your first post, it looks like the issue is intermittent because you can't always reproduce it?

Cheers,
Knack

@gitazem
Copy link
Contributor

gitazem commented Feb 27, 2017

Hello guys,
I have the same problem! So +1..
I need help. I need to download big reports Its happen every time on same account. (I can reproduce it).

@Code-Working do you find a solution ? i just make a "hard" workaround... i am trying to retry download not only on ApiException but also on Throwable. Sometimes it works. (I can reproduce this because my file is really big 113MB (csv.gz). )

I will send debug info from logs for @fiboknacky because my workaround is really not good.

Downloading report bids_keywords_full AccountId: xxx [2017-02-28 10:39:23] AW_REPORT_DOWNLOADER.WARNING: tsp GuzzleHttp/6.2.1 curl/7.35.0 PHP/7.0.16-2+deb.sury.org~trusty+1 - [28/Feb/2017:10:39:23 +0200] "POST /api/adwords/reportdownload/v201609 HTTP/1.1" NULL NULL first retry [2017-02-28 10:40:53] AW_REPORT_DOWNLOADER.WARNING: tsp GuzzleHttp/6.2.1 curl/7.35.0 PHP/7.0.16-2+deb.sury.org~trusty+1 - [28/Feb/2017:10:40:53 +0200] "POST /api/adwords/reportdownload/v201609 HTTP/1.1" NULL NULL second retry [2017-02-28 10:41:57] AW_REPORT_DOWNLOADER.INFO: tsp GuzzleHttp/6.2.1 curl/7.35.0 PHP/7.0.16-2+deb.sury.org~trusty+1 - [28/Feb/2017:10:41:57 +0200] "POST /api/adwords/reportdownload/v201609 HTTP/1.1" 200 118445655
Third retry was successful.
Thank you!

@fiboknacky
Copy link
Member

Hello All,

I've received some more info from @gitazem (thanks for that!), but couldn't reproduce the issue.
The report query I used produced the number of results up to 2 million rows, but the utility could finish the job within several seconds (when saving the results to a file).
It took considerably longer if I used getAsString(), but it didn't freeze.

I'd recommend to consider your query again if it produces too large results.
You could use predicates or shorter date ranges to split your results into manageable sizes.
Please review this section for details.

As you may know, the ReportDownloader uses Guzzle, which in turn uses cURL.
This is the same as ReportUtils in the deprecated branch. So, for now, I can't think of other factors that would differentiate the two's performances.

And for:

I can't reproduce why I'm getting this error, but setting $response = null in GuzzleLogMessageHandler.php, line 58-62 seems to be not so good idea since the rewind_body() function of Guzzle expects a MessageInterface and not null.

I'll take a look at this.
This seems not so good as you said, in case we have a double issue inside that part that makes $reason not an instance of RequestException.

Cheers,
Knack

@gitazem
Copy link
Contributor

gitazem commented Mar 2, 2017

Hello Knack,

I wrote email again, tried to explain how to reproduce this.

And for:
I can't reproduce why I'm getting this error, but setting $response = null in GuzzleLogMessageHandler.php, line 58-62 seems to be not so good idea since the rewind_body() function of Guzzle expects a MessageInterface and not null.
This is totally related problem. I reproduce this all the time. If first problem will happen then error goes there. It should be handled sure, but problem still exist. Servers not responding sometimes.

Best,
Gita

@fiboknacky
Copy link
Member

Hello Gita,

Thanks for active communication.
You're right that the issues are related.

For the second issue, it's not so hard to fix but for the first one, it's still tricky.
I'm thinking about that too.

Best,
Knack

@gitazem
Copy link
Contributor

gitazem commented Mar 2, 2017

Hello,

Yes second issue is not hard to fix we will not get fatal errors, but what for it ? You will log error, but we still don't get results. We just ignore real problem.

Best,
Gita

@fiboknacky
Copy link
Member

Hi Gita,

If at least we get error message, we can have more clues of what happened.

By the way, for this second issue, could you please gather more information for me (e.g., by var_dump)?
What does the exception is that case look like?
Is it just a Throwable object with no other information?

Thanks in advance.

Cheers,
Knack

@gitazem
Copy link
Contributor

gitazem commented Mar 2, 2017

Hey,

var_dump in src/Google/AdsApi/Common/GuzzleLogMessageHandler.php line 73
$response variable returned null. Because there is no response at all.

Throwable class is: TypeError
Because "\GuzzleHttp\Psr7\rewind_body($response);" $response is NULL so its php error.

Class: vendor/guzzlehttp/guzzle/src/Handler/StreamHandler.php:309
one time $resource is normal and second time
$resource is false.
screen shot 2017-03-02 at 14 30 49

@fiboknacky
Copy link
Member

Hello Gita,

Thanks for more information.
Let me take some time to see what happens.

Best,
Knack

@fiboknacky
Copy link
Member

Hello all,

Could you please try setting the timeout options in ReportDownloader?
For example, if you use v201702, could you please try adding the following command before this line?

$requestOptions['stream_context']['http']['timeout'] = "YOUR_TIMEOUT";

I've tested intensively so far, and it seems that when you download large reports, the default timeout in your system might not be enough to ensure complete communication between the servers and your application.
I'm faced with this issue in one computer, but not in another one.

The timeout settings of my two computers are quite different. The one that is faced with the issue has the settings as 60 seconds. Another computer has 480 seconds and is not faced with this issue.
So, please try adjusting your timeout value accordingly.

In the long run, I'd open this option settable via ReportDownloader so you don't need to hack into this class directly.

Cheers,
Knack

@gitazem
Copy link
Contributor

gitazem commented Mar 6, 2017

Hello Knack,

Yes, you are right. This helped. I had this in mind, but have not tested yet. Perfect!

Now i created workaround while you will implement timeout option :

ini_set("default_socket_timeout", "360");

Thank you !

Best,
Gita

@fiboknacky
Copy link
Member

Hello Gita,

Thanks for confirming that it works.
I'm working to provide this option in the ReportDownloader.

@Code-Working Could you please try this method and let me know if it works for you?

Best,
Knack

@Code-Working
Copy link
Author

Hello,

sorry I was on vacation.
I will try the workaround asap.

@Code-Working
Copy link
Author

Hello again and sorry for the late response.

I've tried out both solutions ini_set('default_socket_timeout', 900) and $requestOptions['stream_context']['http']['timeout'] = "900";

Both solutions are working and I'm able to download the reports now.

In my special case it turned out that even 600 seconds are too short, increasing to 900 seems to be ok for now. I think I will increase it to 3600 seconds in production just to be sure.
Do you know if there are some limits/timeouts on the Google Servers?

I also tried setting ini_set('default_socket_timeout', -1) to disable socket timeouts but this seemed to cause SSL connection errors.

Best,
Code-Working

@ynizon
Copy link

ynizon commented Apr 21, 2017

Hi, i have the same problem.
I have taken the example of Google PHP packages: v201702\Reporting\DownloadCriteriaReportWithSelector.php
I have updated the code to filter with some customerId like this:
$tabs = array("49533387XX","60218998XX","68597006XX","67865223XX","11076863XX");
foreach ($tabs as $customerId){
$session = (new AdWordsSessionBuilder())
->fromFile($file)
->withOAuth2Credential($oAuth2Credential)
->withReportSettings($reportSettings)
->withClientCustomerId($customerId)
->build();
}
When i try this , on Windows, all Guzzle Http request are very quick and all in 200.
But when i try this on Debian, it's very slow. Randomly, the first, or the second give me a null and crash...

My exports are not big (less than 1k).
Changing timeout is a solution, but i don't understand why there is a great difference between OS with the same code. Do you know if apache manage queue differently ?

Thanks

@fiboknacky
Copy link
Member

Unfortunately, I don't know that either. As far as I know, PHP and Guzzle seem to behave quite differently between OSes and environments. So, adjusting the configs for each OS is quite necessary, in my opinion.

@davidcv91
Copy link

I have this problem too and 'default_socket_timeout' solution is not working on my side.
I'm running the latest version of Google Ads API PHP client library (v201702) and PHP 5.5.38. Anyone could help me with that?
This is the error:

Catchable fatal error: Argument 1 passed to GuzzleHttp\Psr7\rewind_body() must implement interface Psr\Http\Message\MessageInterface, null given, called in /Applications/MAMP/htdocs/ReportingScripts/GG/vendor/googleads/googleads-php-lib/src/Google/AdsApi/Common/GuzzleLogMessageHandler.php on line 74 and defined in /Applications/MAMP/htdocs/ReportingScripts/GG/vendor/guzzlehttp/psr7/src/functions.php on line 274

@fiboknacky
Copy link
Member

Hi @davidcv91

How long did you set as the timeout?
And did you try what I mentioned here, i.e., setting the timeout value as an option for RequestOptions?

Cheers,
Knack

@davidcv91
Copy link

davidcv91 commented Apr 28, 2017

Hi @fiboknacky

I've tried both solutions with a timeout of 900, like @Code-Working explained on this comment:

ini_set('default_socket_timeout', 900);
$requestOptions['stream_context']['http']['timeout'] = "900";

Regards,
David

@Code-Working
Copy link
Author

@davidcv91 did you try setting it to 3600 seconds?
As I wrote above, I had some problems with 600 seconds. So depending on your or the Google servers 900 might still be too low.

@fiboknacky
Copy link
Member

Hi All,

We've opened the way for providing custom request options for downloading reports in RequestOptionsFactory of v26.0.0, and many people seem to be able to set timeout for downloading reports successfully, so I'll close this issue now.

Cheers,
Knack

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants