簡體   English   中英

Angular Universal + Firebase Cloud Function 導致超出內存限制

[英]Angular Universal + Firebase Cloud Function causing memory limit exceeded

目前我正在開發一個使用 Firebase 作為后端的 Angular 8 應用程序。

我遵循了Jeff Delaney 的教程,並成功部署了一個名為 ssr 我的快速服務器的雲功能。

一切正常......幾乎! 部署 ssr 函數后,我可以看到我所有雲函數的內存使用量增加,即使是最小的(1 個事務,在事務中有一個 get 和 1 個更新):

函數/src/index.ts

// The Cloud Functions for Firebase SDK to create Cloud Functions and setup triggers.
import * as functions from 'firebase-functions';
// The Firebase Admin SDK to access Firestore.
import * as admin from 'firebase-admin';

admin.initializeApp();

export const ssr = functions.https.onRequest(require(`${process.cwd()}/dist/server`).app);

export const unsubscribeToMeal = functions.region('europe-west1').https.onCall((data) => {
  const mealDoc = admin.firestore().doc('meals/' + data.meal.uid);
  const adminDoc = admin.firestore().doc('users/' + data.meal.adminId);
  return admin.firestore().runTransaction(t => {
    return t.get(mealDoc)
      .then(doc => {
        const meal = doc.data();
        if (doc.exists && meal) {
          const promises = [];
          const participantIndex = meal.users.findIndex((element: any) => {
            return element.detail.uid === data.userToUnsubscribe.uid;
          });
          meal.users.splice(participantIndex, 1);
          const pendingRequest = meal.users.filter((user: any) => user.status === 'pending').length > 0;
          const p4 = t.update(mealDoc, { 'users': meal.users, 'participantId': admin.firestore.FieldValue.arrayRemove(data.userToUnsubscribe.uid), 'nbRemainingPlaces': meal['nbRemainingPlaces'] + 1, 'pendingRequest': pendingRequest })
          promises.push(p4);
          if (promises.length > 0) {
            return Promise.all(promises)
              .then(() => console.log('user unsubscribed'))
              .catch((err: any) => console.log('error unsubscribing user : ' + data.userToUnsubscribe.first_name + ' ' + data.userToUnsubscribe.last_name + ' of the meal ' + meal.uid + '. Err : ' + err))
          }
          else {
            // doc.data() will be undefined in this case
            throw new functions.https.HttpsError('not-found', 'no such document!');
          }
        } else {
          // doc.data() will be undefined in this case
          console.log('doc does not exist');
          throw new functions.https.HttpsError('not-found', 'no such document!');
        }
      })
  })
});

觸發 unsubscribeToMeal 函數從沒有部署 ssr 函數的 60MB 內存使用量增加到 240MB 內存使用量。

所以我想知道發生了什么? 看起來 express 服務器應用程序是每個雲功能實例上的引導程序,這會導致內存使用量增加和計費增加。

正如 Doug Stevenson在這里解釋的那樣,我限制了全局變量以最小化冷啟動,所以不應該是那樣。

服務器.ts

(global as any).WebSocket = require('ws');
(global as any).XMLHttpRequest = require('xhr2');

import 'zone.js/dist/zone-node';
import 'reflect-metadata';
import { enableProdMode } from '@angular/core';
import * as express from 'express';
import { join } from 'path';

// Faster server renders w/ Prod mode (dev mode never needed)
enableProdMode();

// Express server
export const app = express();
import * as cookieParser from 'cookie-parser';
import { from } from 'rxjs';
app.use(cookieParser());

const PORT = process.env.PORT || 4000;
const DIST_FOLDER = join(process.cwd(), 'dist/browser');

// * NOTE :: leave this as require() since this file is built Dynamically from webpack
const { AppServerModuleNgFactory, LAZY_MODULE_MAP, ngExpressEngine, provideModuleMap } = require('./dist/server/main');


// Our Universal express-engine (found @ https://github.com/angular/universal/tree/master/modules/express-engine)
app.engine('html', ngExpressEngine({
  bootstrap: AppServerModuleNgFactory,
  providers: [
    provideModuleMap(LAZY_MODULE_MAP)
  ]
}));

app.set('view engine', 'html');
app.set('views', DIST_FOLDER);

// Example Express Rest API endpoints
// app.get('/api/**', (req, res) => { });
// Serve static files from /browser
app.get('*.*', express.static(DIST_FOLDER, {
  maxAge: '1y'
}));

// All regular routes use the Universal engine
app.get('*', (req: express.Request, res: express.Response) => {
  res.render('index2', {
    req
  });
});

// Start up the Node server
app.listen(PORT, () => {
  console.log(`Node Express server listening on http://localhost:${PORT}`);
});

任何解決方案仍然具有低內存使用率(不增加函數的內存限制)並且同時具有用於角度通用的快速服務器的 ssr 函數?

我認為內存的增加並不意外。 您的教程中有說明:

Angular 是一個客戶端框架,旨在在瀏覽器中運行應用程序。 Universal 是一個可以在服務器上運行你的 Angular 應用程序的工具,...

因此,使用 SSR 解決方案,您將運行 angular 應用程序表單客戶端移動到服務器,因此所有代碼在客戶端正常運行,現在在服務器上運行。 我不認為有可能在不保留執行它所需的資源的情況下運行某些東西......

也許在這種特殊情況下,AppEngine 會更好地部署它......我希望它能以某種方式幫助你:)

與 firebase 社區取得聯系后:“使用 firebase deploy --only 函數將為您的所有函數重新部署代碼,所使用的內存將是所有這些函數加載在一起的累積總和”。 因此,解決方案是將函數拆分為不同的文件,並使用帶有 if 語句的 process.env.[functionName] ,如此處所述,以避免增加 expressFunction 的內存。

是的 vitooh! 您需要將每個函數拆分為一個 ts 或 js 文件。 這是我的新結構:

  • /職能
    • /源
      • 索引.ts
      • /my_functs
        • ssr.ts
        • unsubscribeToMeal.ts
        • ... 其他功能

每個函數文件都需要以exports = module.exports = functions...開頭,例如,這是我新的express函數的代碼(你可以比較我在第一篇文章中的代碼)

functions/src/my_functs/ssr.ts file
// The Cloud Functions for Firebase SDK to create Cloud Functions and setup triggers.
import * as functions from 'firebase-functions';

exports = module.exports = functions.https.onRequest(require(`${process.cwd()}/dist/server`).app);

不要忘記在每個文件中導入所需的內容,例如“從 'firebase-functions' 導入 * 作為函數;”。 我還更改了我的 index.ts 文件,該文件在部署到 firebase 時使用: firebase deploy --only 函數並從函數文件夾中安裝了 glob (npm i glob)。

functions/src/index.ts file

const glob = require("glob");
if (process.env.FUNCTION_NAME) {
  // Specific function requested, find and export only that function
  const functionName = process.env.FUNCTION_NAME;
  const files = glob.sync(`./my_functs/${functionName}.@(js|ts)`, { cwd: __dirname, ignore: './node_modules/**' });
  const file = files[0];
  exports[functionName] = require(file);
} else {
  // Name not specified, export all functions
  const files = glob.sync('./my_functs/*.@(js|ts)', { cwd: __dirname, ignore: './node_modules/**' });
  for (let f = 0, fl = files.length; f < fl; f++) {
    const file = files[f];
    const functionName = file.split('/').pop().slice(0, -3); // Strip off '.(js|ts)'
    exports[functionName] = require(file);
  }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM