Можно ли экспортировать Cloud SQL синхронно?Или как можно отследить и повторить ошибки, если они асинхронные? - PullRequest
0 голосов
/ 15 мая 2019

Краткая сводка

Экспорт SQL в облаке может иногда завершаться неудачей.
Можно ли заставить запросы экспорта работать синхронно, чтобы сбои легко повторить?
Или есть хороший способ повторить экспорт васинхронный подход?

Полное описание

Я переносу код из App Script в Node.js и столкнулся с проблемой.Код экспортирует результаты запроса Cloud SQL в файл CSV.Облачный SQL не может выполнять параллельный экспорт, поэтому иногда возникает следующая ошибка:

Error: Operation failed because another operation was already in progress.

В скрипте приложения подход состоял в том, чтобы подождать 6 секунд, а затем повторить попытку с ограничением в 10 попыток.

Это было просто, потому что код вел себя синхронно:

for(exportAttempt=1; exportAttempt<=10; exportAttempt++) {
    Utilities.sleep(6000); 
    // Use the url fetch service to issue the https request and capture the response
    var response = UrlFetchApp.fetch(api, parameters);
    response = JSON.parse(response);

    if(exportAttempt == 10) {
        throw('Exceeded the limit of 10 failed export requests to REST API.');
    } 
    if(response.status != undefined) {
        _log_('DEBUG', 'Export attempt ' + exportAttempt + ' successful.');
        exportAttempt=10;
    }
    if(response.error != undefined) {
        _log_('DEBUG', 'Attempt number ' + exportAttempt + ' errored. ' + JSON.stringify(response));
    }
} 

Репликация функциональности экспорта в Node.js была возможна со следующим кодом, но он ведет себя асинхронно:

var {google} = require('googleapis');
var sqladmin = google.sqladmin('v1beta4');

var uri = 'gs://' + csBucket + '/' + csFileName;

google.auth.getApplicationDefault(function(err, authClient) {
    if (err) {
        _log_('ERROR', 'Authentication failed because of ' + err);
        return false;
    }

    if (authClient.createScopedRequired && authClient.createScopedRequired()) {
        var scopes = [
            'https://www.googleapis.com/auth/cloud-platform',
            'https://www.googleapis.com/auth/sqlservice.admin'
        ];    
        authClient = authClient.createScoped(scopes);
    }

    var request = {
        project: projectId,
        instance: sqlInstance, 

        resource: {
            exportContext: {
                kind: "sql#exportContext",
                fileType: fileType,
                uri: uri,
                databases: [sqlSchema], 
                csvExportOptions: {
                    selectQuery: exportSQL 
                }
            }
        },
        auth: authClient
    };

    sqladmin.instances.export(request, function(err, result) {
        if (err) {
            //The problem with the exception is that it stops the Cloud Function.
            //It isn't thrown up to the parent/calling function to be used for a retry. 
            _log_('ERROR', 'Export failed because of ' + err);
            throw(err)                
        } else {
            _log_('DEBUG', 'result');
            _log_('DEBUG', result);
        }
    });
});

Это означает, что ошибка вызывает немедленный сбой.Я не могу найти способ выдать ошибку до родительской / вызывающей функции, чтобы справиться с повторной попыткой.

1 Ответ

0 голосов
/ 16 мая 2019

Решение

В конце я попробовал рекурсивный подход. Изначально я не думал, что это возможно, потому что компилятор жаловался на использование async и await, но мне просто нужно было найти правильное место для их размещения.

sqladmin.instances.export(request, async function(err, result) {
    if (err) {
        if(attempt == 10) throw('Retries exceeded');

        _log_('ERROR', 'Export error.  Retry attempt ' + attempt);
        await _sleep_(6000);                
        attempt++;
        await exportCSV(<all>,<the>,<same>,<parameters>,<passed>,<in>,attempt);
    } else {
        _log_('DEBUG', 'result');
        _log_('DEBUG', result);
    }

...

function _sleep_(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}
...