Тайм-аут в функциях Firebase - PullRequest
0 голосов
/ 25 февраля 2020

Я тестирую набор облачных функций локально и, при необходимости, имею эмуляторы для настройки базы данных, Firestore, Hosting, PubSub и Functions. Я пытаюсь сделать следующее:

  1. В файле functions/index.js я импортирую модули, которые используются в качестве триггера HTTP для разных конечных точек.
  2. Я использую инъекцию зависимости ( DI) для предоставления модулям доступа ко всем распространенным зависимостям из файла functions/index.js.

Мой подход к коду пока:

функции / индекс. js

const functions = require('firebase-functions');
const admin = require('firebase-admin');
const express = require('express');
const cors = require('cors');
const session = require('express-session');
const firestoreSession = require('connect-session-firebase')(session);
const cookieParser = require('cookie-parser');
const { validationResult } = require('express-validator');

const ref = admin.initializeApp({
    databaseURL: 'http://localhost:8080',
    credential: admin.credential.cert('path/to/credential.js')
});

// services
const UserService = require('./user/index')({
    express, cookieParser, cors, ref,
    session, firestoreSession, validationResult
});

exports.user = functions.https.onRequest(UserService);

Триггеры HTTP-запроса являются экземплярами express. Я внедряю зависимости (как в UserService), а затем выставляю триггер под URL BASE_URL / user. Есть несколько других подобных сервисов. Внутри UserService у меня есть следующее:

module.exports = function({
    express, cors,
    session, firestoreSession,
    cookieParser, validationResult, ref
}) {
    const Validators = require('./validators');

    const userserv = express();
    userserv.use(cors({ origin: true }));
    userserv.use(session({
        name: 'user_session',
        resave: true,
        saveUninitialized: true,
        secret: 'TOKEN_SECRET_HERE',
        store: new firestoreSession({
            database: ref.database()
        })
    }));

    userserv.post('/login', (req, res, nxt) => {
        res.json({
            status: 200,
            message: 'Logged In'
        });
    });
    // ... other route handlers
    return userserv;
};

функции / пользователь / индекс. js

Теперь, когда я запускаю эмуляторы, все начинается нормально. Когда я отправляю запрос POST с помощью curl, функция просто останавливается, пока не истечет время ожидания. Вот пример запроса curl:

curl -X POST -H 'Content-Type:application/json' -d '{}' http://localhost:5001/<App>/<region>/user/login

Когда происходит тайм-аут или когда я вручную останавливаю эмуляторы, я вижу ответ JSON, как и ожидалось. Не уверен, что вызывает зависание функции. Полагаю, что-то связано с настройкой базы данных для хранилища сеансов, в результате чего функция вводит бесконечный l oop запросов. Некоторые предложения будут с благодарностью.

Примечание. Я использую DI, потому что хочу управлять импортом в одном файле, а также делиться хранилищем сеансов между службами. В способе, который я видел при настройке хранилища сессий firebase, используется ссылка на приложение из admin.initializeApp, поэтому было бы легко передать это в качестве аргумента всем импортированным сервисным модулям.

Обновление 1

Проблема определенно связана с промежуточным программным обеспечением сеанса. Закомментирование кода настройки сеанса в functions/user/index.js не приводит к зависанию сервера при выполнении запроса, и ответ отправляется быстро, как и ожидалось.

Обновление 2 После просмотра журналы отладки, это то, что казалось "проблематичным c" из database-debug.log:

WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by io.netty.util.internal.ReflectionUtil (file:/home/zerocool/.cache/firebase/emulators/firebase-database-emulator-v4.3.1.jar) to field sun.nio.ch.SelectorImpl.selectedKeys
WARNING: Please consider reporting this to the maintainers of io.netty.util.internal.ReflectionUtil
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release

Ответы [ 2 ]

0 голосов
/ 27 февраля 2020

Хорошо, я наконец-то смог запустить функции и получить ожидаемый результат, как и ожидалось. Как указано в обновлениях к исходному сообщению, проблема была связана с настройкой магазина connect-session-firebase. Для локальной настройки я попробовал следующее:

// ... other code unchanged
const ref = admin.initializeApp({
    // remove the following line
    // databaseURL: 'http://localhost:8080',
    credential: admin.credential.cert('path/to/credential.js')
});

Кроме того, в соответствии с документацией для connect-session-firebase, мне нужно настроить файл .env со следующим:

FIREBASE_DATBASE_URL=http://localhost:9090
FIREBASE_SERVICE_ACCOUNT=./serviceAccount.json

База данных работала правильно, и запрос к файлу sessions.json дал запись, как и ожидалось. Также проверил это после развертывания (для этого мне не понадобился файл .env, и мне пришлось изменить databaseURL на фактический URL базы данных для проекта). Спасибо всем за уделенное время и помощь.

0 голосов
/ 25 февраля 2020

У меня недостаточно репутации, чтобы комментировать.

Вы установили ключ?

const ref = firebase.initializeApp({
  credential: firebase.credential.cert('path/to/serviceAccountCredentials.json'),
  databaseURL: 'https://databaseName.firebaseio.com'
});

Также попробуйте передать флаги: resave и saveUninitialized

express()
  .use(session({
    store: new FirebaseStore({
      database: ref.database()
    }),
    secret: 'keyboard cat'
    resave: true,
    saveUninitialized: true,
    cookie: {maxAge : 60000,
        secure: false,
        httpOnly: false }
  }));

Проверьте безопасность:

{
  "rules": {
    ".read": "false",
    ".write": "false",
    "sessions": {
      ".read": "false",
      ".write": "false"
    },
    "some_public_data": {
      ".read": "true",
      ".write": "auth !== null"
    }
  }
}

Запустите CORS с этими флагами:

app.use(function(req, res, next) {
    res.header('Access-Control-Allow-Credentials', true);
    res.header('Access-Control-Allow-Origin', req.headers.origin);
    res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
    res.header('Access-Control-Allow-Headers', 'X-Requested-With, X-HTTP-Method-Override, Content-Type, Accept');
    if(req.session){
      res.header("mytoken",req.token);
    }
    next();
});

РЕДАКТИРОВАТЬ 1: Отправка сообщения внутри Cors

const cors = require('cors')({origin: true});

userserv.post('/login', (req, res) => {    
     cors(req, res, () => {

      console.log('Sending POST inside CORS')

      res.status(200).send({message: 'Logged In'})

    });            
 });
...