1

This is an extension of the following question. I can't use it because PropertiesService and ScriptApp is not supported in Adwords and I didn't find anything relevant so far on the question adapted to Adwords.

I have an Adwords script that constantly gets the error Exceeded maximum execution time. For an MCC accounts, I think the maximum time execution is 30 minutes. Does anyone know if there is a way to extend this time limit? Or perhaps is there a way to call the Adwords script again and it picks up from where it left off? Queuing? Could I use an MCCScript with Google-Apps-Script?

Here is what I have done so far ...

function timeDrivenTrigger(myFunct) {
    var REASONABLE_TIME_TO_WAIT = 4*6000;
    var MAX_RUNNING_TIME = 1*6000;

    var ss = SpreadsheetApp.openByUrl('https://docs.google.com/spreadsheets/d/1sYQ__CM33oL2OLzbScQEdcQ6LvDxJCohP024vdSGfSI/edit#gid=0');
    var sheet = ss.getSheets()[0];
    var cell = sheet.getRange('A1');

    var startTime= (new Date()).getTime();

    myFunct;

    var startRow= cell.getValue() || 1;
    for(var ii = startRow; ii <= 10000; ii++) {
        var currTime = (new Date()).getTime();
        if(currTime - startTime >= MAX_RUNNING_TIME) {
            cell.setValue(ii);
            ScriptApp.newTrigger("runMe")
                .timeBased()
                .at(new Date(currTime+REASONABLE_TIME_TO_WAIT))
                .create();
            break;
        } 
    }
}

UPDATE WITH PARALLEL EXECUTION

Here is my whole code ...

//Your build Google-Spreadsheet
var SPREADSHEET_URL = "https://docs.google.com/spreadsheets/d/1k4o_8O_11OvhZRergefWKgXQ8_XxIs7D31-NV9Ove-o/edit#gid=749396300";

//Fetch and convert data in a JSON structure 
var spreadsheet = SpreadsheetApp.openByUrl(SPREADSHEET_URL);
var sheet = spreadsheet.getSheetByName('Campaigns');
var data = sheet.getRange("A:C").getValues();
var accountList = accountsListing(data);

accountList= accountList.map(function (el) {
    return el.trim();
});

function main() {

    accountIdList = [];
    accountItr = MccApp.accounts().get();
    while(accountItr.hasNext()) {
      account = accountItr.next();
      if (accountList.indexOf(account.getName()) > -1) {
        accountIdList.push(account.getCustomerId())
      }
    }

    if(accountList.length > 0) {
        var accountSelector = MccApp.accounts()
            .withIds(accountIdList)
            .withLimit(40);

        accountSelector.executeInParallel('adjustCPCmax');
    }

}


String.prototype.format = function () {
  var i = 0, args = arguments;
  return this.replace(/{}/g, function () {
    return typeof args[i] != 'undefined' ? args[i++] : '';
  });
};


function isBlank(line) {
    return line[0].trim() === '' && line[1].trim() === '';
}


function parseData(data) {

    const output = {};
    var currentGroupName = '';

    data.forEach(function(line, index){
        if (isBlank(line) || index === 0){
            return; 
        }

        if (line[0].trim().length > 1) {
            currentGroupName = line[0].trim();
        }

        output[currentGroupName] = output[currentGroupName] || {};

        output[currentGroupName][line[1]] = line[2];
    });

    return output;
}


function accountsListing(data) {
    function isBlank(line){
        return line[0].trim() === '';
    }

    const output = [];

    data.forEach(function(line, index) {
        if (isBlank(line) || index === 0) {
            return;
        }

        output.push(line[0])
    });

    return output
}


function parseKeyword(keyword, keywordId, maxCPC) {

    Logger.log('THE NAME OF THE KEYWORDID IS ' + keywordId + '\n')

    var report = AdWordsApp.report(
               'SELECT Id, Criteria, CampaignName, CpcBid, FirstPageCpc, FirstPositionCpc, TopOfPageCpc, Criteria ' +
               'FROM   KEYWORDS_PERFORMANCE_REPORT ' +
               'WHERE ' + 
               'Id = ' + keywordId);
    var rows = report.rows();
    while(rows.hasNext()) {
        var row = rows.next();
        var keywordIdReport = row['Id'];
        var keywordNameReport = row['Criteria'];
        var campaignName = row['CampaignName'];
        var cpcBid = row['CpcBid'];
        var firstPageCpc = row['FirstPageCpc'];
        var firstPositionCpc = row['FirstPositionCpc'];
        var topOfPageCpc = row['TopOfPageCpc'];

        Logger.log('INFO')
        Logger.log(keyword.getText())
        Logger.log(keywordId)
        Logger.log(keywordNameReport)
        Logger.log(keywordIdReport + '\n')

        if (keywordId === keywordIdReport) {

            if (firstPositionCpc && (firstPositionCpc > 0 && firstPositionCpc <= maxCPC)) {
                var newCPC = firstPositionCpc;
            } else if (topOfPageCpc  && (topOfPageCpc > 0 && topOfPageCpc <= maxCPC)) {
                var newCPC = topOfPageCpc;
            } else if (firstPageCpc && (firstPageCpc > 0 && firstPageCpc <= maxCPC )) {
                var newCPC = firstPageCpc;
            } else {
                var newCPC = minCPC;
            }

            Logger.log('KeywordIdReport :' + keywordIdReport)
            Logger.log('campaignName :' + campaignName)
            Logger.log('CPCbid :' + cpcBid)
            Logger.log('firstPositionCpc : ' + firstPositionCpc)
            Logger.log('topOfPageCpc : ' + topOfPageCpc)
            Logger.log('firstPageCpc : ' + firstPageCpc)
            Logger.log('NewCPC : ' + newCPC + '\n')

            keyword.bidding().setCpc(newCPC)
            break;
        }
    }
}


function getMaxCPC(account, campaign) {
    var cleanData= parseData(data);

    //Formatting account and campaign
    var account = '{}'.format(account.getName())
    var campaign = '{}'.format(campaign.getName())

    Logger.log('Account :' + account)
    Logger.log('Campaign :' + campaign + '\n')

    return cleanData[account][campaign];
}


function adjustCPCmax() {
    //min CPC
    var minCPC = 0.50;

    var account = AdWordsApp.currentAccount();
    Logger.log('=================================' + account.getName() + "=======================================")
    var campaignIterator = AdWordsApp.campaigns().get();
    while (campaignIterator.hasNext()) {
        var campaign = campaignIterator.next();
        try {
            var maxCPC = getMaxCPC(account, campaign)
        }
        catch(e) {
        }

        if (maxCPC) {
            Logger.log('The entrence worked with max CPC : ' + maxCPC + '\n')
            keywordIterator = campaign.keywords().get();

            var startTime= (new Date()).getTime();
            while (keywordIterator.hasNext()) {
                var keyword= keywordIterator.next()
                var keywordId = Number(keyword.getId()).toPrecision()

                parseKeyword(keyword, keywordId, maxCPC);
            }
        }
    }
}

Be aware that this code will work in the MCC script environment. It could work for any account from a Google spreadsheet.

P.S. This following question gave me a good idea how to process, but I want to know your suggestions.

Dave
  • 85
  • 10
  • 1
    I notice you never actually invoke `myFunct`. `myFunct;` is a no-op, not a call. Also, you iterate to `10000` but don't actually attempt to do anything until 1 second has passed. My guess is that you iterate the 10000 rows in a few milliseconds and never actually enter the `if` statement. **Edit** Upon viewing the linked question, you failed to read the notice on the answer: _This is not a one-size-fit-all solution, if you post your code people would be able to better assist you._ Your comment that "Here is what I have done so far" is literally copy and paste code from someone else's answer. – Patrick Roberts Nov 15 '17 at 20:09
  • @PatrickRoberts I am being asked to put some simple code in order to facilitate the analysis of the question, but it is with pleasure that I will reveal my code. I show you that in two minutes. My code is centralized inside ajustCPCMax() – Dave Nov 15 '17 at 20:26
  • @PatrickRoberts Do you have a good solution? ;) Handling multiple accounts in parallel? – Dave Nov 15 '17 at 21:52
  • No, unfortunately I don't have much experience with google adwords API, but I was glad to push your question in this direction because what you had before was not going to allow you to receive any helpful feedback. If you still don't get any feedback in a few days, I'd be happy to put a bounty on this, just ping me again when the question is eligible for one. – Patrick Roberts Nov 15 '17 at 22:09
  • My adwords script usually run for more than 50 accounts. To allow parallel processing of functions, I run the script for max 50 accounts. When the account is done, it will mark the account as `done` in a spreadsheet. On next run of the script, it will check what accounts have not been marked as `done` yet, and only execute the script for those accounts. This technique may be a solution to your issue. – Casper Nov 16 '17 at 12:52
  • Thanks Casper, and in fact this is exactly what I have done in my code. Do you feel able to check my code? What changes can I make? I will modify my code for that. – Dave Nov 16 '17 at 12:58

0 Answers0