Тайм-аут аутентификации GCP при импорте - PullRequest
0 голосов
/ 18 июня 2020

Я импортирую 16 000 записей из CSV в Firestore, используя простой скрипт узла в GCP CLI.

CSV имеет четыре столбца, каждый из которых записан как новый do c в коллекции. Мне нужно обрабатывать CSV асинхронно, поскольку каждая строка, записанная из CSV, связана с данными в предыдущей строке. В результате импорт занимает более 5 часов.

Процесс постоянно завершается ошибкой со следующей ошибкой: Ошибка: 16 НЕАУТЕНТИЧНО: запрос содержит недопустимые учетные данные для аутентификации. Ожидаемый токен доступа OAuth 2, логин Cook ie или другие действительные учетные данные для аутентификации.

Я подозреваю, что это связано с тем, что, поскольку это длинная задача asyn c, срок действия токена аутентификации истекает. Из того, что я прочитал, токены аутентификации имеют срок службы 1 час.

Я упростил свой код ниже, чтобы смоделировать проблему импорта CVS. При запуске в командной строке Google Cloud Platform воспроизводится ошибка.

const {Firestore} = require('@google-cloud/firestore');
const db = new Firestore();
var previous = '';

async function processRecord(record) {
    console.log(record);
    console.log(record);
    let collectionRef = db.collection('groups');
    const snapshot = await collectionRef.where('name', '==', 'World').get();
    let data = {
        name: record,
        previous: previous,
        created: Firestore.Timestamp.now()
    }
    let docRef = await db.collection('testing').add(data);
    previous = docRef.id;
}

async function importCsv(csvFileName) {
    var records = [];
    for(var i = 0; i < 16000; i++) {
        records.push(`Filler: ${i}`);
    }

    // const fileContents = await readFile(csvFileName, 'utf8');
    // const records = await parse(fileContents, { columns: true });

    for (const record of records) {
        await processRecord(record);
    }
    console.log(`Processed ${records.length} records`);
}

importCsv(process.argv[2]).catch(e => console.error(e));

Что я могу сделать, чтобы завершить импорт?

1 Ответ

1 голос
/ 18 июня 2020

EDITED: изменен весь ответ после предоставления дополнительных сведений (пример кода и лучшее описание требований)

Лучший способ избежать ошибок из-за истечения срока действия токена аутентификации это сделать загрузку быстрее (5 часов для 16k - слишком много времени). Этого можно добиться разными способами, но после просмотра предоставленного кода я создал два сценария nodejs, которые могут удовлетворить ваши потребности в создании «обратного связанного списка», не занимая более 1 минуты для загрузки всего набора из 16 тыс. Записей *. 1005 *

Пояснение: Создание записи и чтение ее в одной транзакции - медленный подход, лучше создать записи, а затем запросить полный набор данных и соответствующим образом обновить. Также настоятельно рекомендуется использовать пакеты для операций записи и обновления, поскольку библиотека на стороне сервера выполняет параллельную индивидуальную запись, дополнительную информацию об этом можно найти по следующей ссылке: Пакетные записи :

Для массового ввода данных используйте клиентскую библиотеку сервера с параллельной индивидуальной записью. Пакетная запись работает лучше, чем сериализованная запись, но не лучше, чем параллельная запись. Вы должны использовать клиентскую библиотеку сервера для операций с массовыми данными, а не мобильный / веб-SDK.

Скрипт: Первая часть - загрузка всего набора данных, я использовал фиктивная нагрузка, представленная в вашем коде, чтобы проиллюстрировать это, однако вы можете заменить переменную records загруженными строками из вашего файла csv. Также обратите внимание, что я использую индекс numeri c для заполнения поля previous, это важно для отслеживания порядка загрузки записей.

batch_writing. js

const {Firestore} = require('@google-cloud/firestore');
const firestore = new Firestore();
async function batch_writting() {
    var records = [];
    let writeBatch = firestore.batch();

    for(var i = 0; i < 17000; i++) {
        records.push(`Filler: ${i}`);
    }
    let index = 0;
    for (const record of records) {
        let documentRef = firestore.collection('testing').doc();
        let data = {
            name: record,
            previous: index,
            created: Firestore.Timestamp.now()
        }
        writeBatch.create(documentRef,data);
        if((index+1) % 500 === 0){
            writeBatch.commit().then(() => {
                console.log('Successfully executed batch.');
            }).catch(e => console.error(e));
            writeBatch = firestore.batch();
        }
        index++;
    }
    writeBatch.commit().then(() => {
        console.log('Successfully executed batch.');
    }).catch(e => console.error(e));
}

batch_writting().catch(e => console.error(e));

После того, как часть записи завершена и поле previous заполнено увеличивающимся индексом, мы можем перейти к опросу всего недавно созданного набора данных и перейти к обновлению ключа previous с правильным идентификатором документа из предыдущей загруженной строки. Это делается путем упорядочивания запроса по полю previous, которое было заполнено в инкрементном индексе. Обратите внимание, что первая запись будет иметь значение numeri c, равное 0, так как у нее нет предыдущей загруженной строки.

update_writing. js

const {Firestore} = require('@google-cloud/firestore');
const firestore = new Firestore();
async function batch_update(){
    let query = firestore.collection('testing');
    query.orderBy('previous', 'asc').get().then(querySnapshot => {
        let writeBatch = firestore.batch();
        let previousID = 0;
        let index = 0;
        querySnapshot.forEach(documentSnapshot => {
            writeBatch.update(documentSnapshot.ref,{previous: previousID})
            previousID = documentSnapshot.id;
            if((index+1) % 500 === 0){
                writeBatch.commit().then(() => {
                    console.log('Successfully executed batch.');
                }).catch(e => console.error(e));
                writeBatch = firestore.batch();
            }
            index++;
        });
        writeBatch.commit().then(() => {
            console.log('Successfully executed batch.');
        }).catch(e => console.error(e));
    });
}

batch_update().catch(e => console.error(e));

Если вам нужно запросить больше полей или других коллекций, не стесняйтесь изменять сценарии, но не забывайте избегать запроса определенного c поля и отдавайте предпочтение запросам, которые собирают полный набор данных. Также, если вам нужны дополнительные записи, используйте пакетные записи.

...