Tuesday, 12 May 2015

Avoiding Script Timeouts - Part 1

Avoiding Script Timeouts - Part 1


Scripts are possibly the most useful tool for managing larger Accounts.  Scripts can apply complex processes automatically and reliably across a large number of AdWords elements and allow you to concentrate on what you do best - marketing.  However, ironically, when the Account is very large and/or the script complex, you may find your marvellous script consistently "times out".  At the time of writing, scripts can only run for 30 minutes before automatically terminating; this obviously means there's the potential for an unknown percentage of your AdWords elements to remain unprocessed but it also often means important logging information is lost (as "final" logs are never reached).

This post will hopefully give you some pointers to ensure your scripts run as quickly as possible and the next will give you some options for dealing with scripts that simply cannot be made to run under 30 minutes.  So, let's start with the tips:

#1 - Good structure

All programming benefits from a good structure and with AdWords scripts the structure can be particularly important in terms of run time.  Most scripts will use some form of selector to fetch AdWords elements (Campaigns, Groups, Keywords, etc.) and then process them in some way but how you fetch these elements can have a big impact on how fast a script runs.  Imagine each selector is like sending an office minion out of the building to get something from a local store; the more often you send that person out the more time it's going to take to complete your task.  So, for example, if you want to work on Keywords, rather than selecting Campaigns, then iterating them to select Ad Groups, then iterating those to select Keywords, look for a method to select the Keywords you need in one selector.  Labels are an excellent way to do this (and you could use another script to apply and/or remove the Labels, of course, running before your main one).

Don't forget things like Campaign and Ad Group names are accessible from Keyword objects so you don't need to iterate Campaigns just to retrieve their names for reporting.

As a rule of thumb, your selector should, as far as possible, select the objects you want to work upon directly and if you're not doing that, you should think about how you could.

#2 - Only select what you need

Make sure your selectors use conditions that ensure they return only the elements you need to work upon.  One very common bad practice (in all programming/scripting) is to fetch a large dataset and then examine each returned element for suitability, discarding those that don't fit.  For example, you may select all the Keywords in a Campaign, then use conditional statements to check whether those Keywords are enabled or if they have impressions, etc.  It is much better practice (and far faster) to include these conditions in the original selector so if you want to work only on Keywords that are enabled, ensure you include these conditions in your selector:

.withCondition("Status = 'ENABLED'")
.withCondition("CampaignStatus = 'ENABLED'")
.withCondition("AdGroupStatus = 'ENABLED'")

If you want to check for clicks or impressions, you can do so, as long as you include a time range in the selector, e.g.

.withCondition("Impressions > 0")
.forDateRange("LAST_30_DAYS")

The same thinking can be applied to all other elements you might select; try to use the selector itself to define your returned objects rather than grabbing a huge bundle then spending ages throwing most of it away.

#3 - Use AdWords API reports

The many prebuilt reports in the API are much faster at retrieving AdWords elements than the normal selectors so where possible, use these reports.  The process of using them within scripts is quite different from a selector but there are plenty of examples on the web and once you've used one, the process is similar for all.  These reports aren't appropriate for all script uses but if you can use one, you should.  See here for a list of available reports.

https://developers.google.com/adwords/api/docs/appendix/reports

#4 - Watch your Logging

Logging is, of course, a vital part of scripting, especially in the development/testing stages but logging has a surprisingly big impact on run time, particularly when the logs are frequent and within a loop.  Try to keep your logging to what is absolutely necessary and once you're sure the script is working correctly, consider whether you can remove any.

#5 - Keep loops clean

Avoid including statements within loops that don't need to be calculated in each iteration.  For example, if you wanted to compare each Keyword's CTR against the average for an entire Campaign, you only need to calculate the Campaign average once, don't include that calculation inside the Keyword iterator.  The script within  a loop should be only that needed for the loop to operate correctly.

#6 - Check for "bloat"

It's very easy when writing script to check for certain conditions (average position vs ROAS or CTR vs number of conversions, etc.) to end up with several conditional statements.  It's just as easy for the final version to end up with redundant conditions.  Make sure all the tests/conditions you apply are unique and where they are, consider whether there's a quicker way to write the same set of conditions.

There are other tips for speeding up scripts that can be learned from the many online pages that teach speed improvement for JavaScript and while some can't be applied to AdWords scripts, most can and I'd recommend some quality time with Google search.  You might try starting with a search on "improve javascript speed".

In the next post I'll look at what you can do if despite your best efforts the script still times out.  Good luck!
Post a Comment