@salesforce/pwa-kit-runtime 3.9.0 → 3.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforce/pwa-kit-runtime",
3
- "version": "3.9.0",
3
+ "version": "3.9.2",
4
4
  "description": "The PWAKit Runtime",
5
5
  "homepage": "https://github.com/SalesforceCommerceCloud/pwa-kit/tree/develop/packages/pwa-kit-runtime#readme",
6
6
  "bugs": {
@@ -46,11 +46,11 @@
46
46
  },
47
47
  "devDependencies": {
48
48
  "@loadable/component": "^5.15.3",
49
- "@salesforce/pwa-kit-dev": "3.9.0",
49
+ "@salesforce/pwa-kit-dev": "3.9.2",
50
50
  "@serverless/event-mocks": "^1.1.1",
51
51
  "aws-lambda-mock-context": "^3.2.1",
52
52
  "fs-extra": "^11.1.1",
53
- "internal-lib-build": "3.9.0",
53
+ "internal-lib-build": "3.9.2",
54
54
  "nock": "^13.3.0",
55
55
  "nodemon": "^2.0.22",
56
56
  "sinon": "^13.0.2",
@@ -58,7 +58,7 @@
58
58
  "supertest": "^4.0.2"
59
59
  },
60
60
  "peerDependencies": {
61
- "@salesforce/pwa-kit-dev": "3.9.0"
61
+ "@salesforce/pwa-kit-dev": "3.9.2"
62
62
  },
63
63
  "peerDependenciesMeta": {
64
64
  "@salesforce/pwa-kit-dev": {
@@ -72,5 +72,5 @@
72
72
  "publishConfig": {
73
73
  "directory": "dist"
74
74
  },
75
- "gitHead": "bb69324df47c107d592f50aa9a5e7069ae89fccd"
75
+ "gitHead": "d982971e3a1cc1f65ce296e526c459b2ea5f83fe"
76
76
  }
@@ -319,6 +319,8 @@ const RemoteServerFactory = exports.RemoteServerFactory = {
319
319
  app.disable('x-powered-by');
320
320
  const mixin = {
321
321
  options,
322
+ // Forcing a GC is no longer necessary, and will be
323
+ // skipped by default (unless FORCE_GC env-var is set).
322
324
  _collectGarbage() {
323
325
  // Do global.gc in a separate 'then' handler so
324
326
  // that all major variables are out of scope and
@@ -883,12 +885,15 @@ const RemoteServerFactory = exports.RemoteServerFactory = {
883
885
  // the response to the browser.
884
886
  context.callbackWaitsForEmptyEventLoop = false;
885
887
  if (lambdaContainerReused) {
886
- // DESKTOP-434 If this Lambda container is being reused,
887
- // clean up memory now, so that we start with low usage.
888
- // These regular GC calls take about 80-100 mS each, as opposed
889
- // to forced GC calls, which occur randomly and can take several
890
- // hundred mS.
891
- app._collectGarbage();
888
+ const forceGarbageCollection = process.env.FORCE_GC;
889
+ if (forceGarbageCollection && forceGarbageCollection.toLowerCase() === 'true') {
890
+ // DESKTOP-434 If this Lambda container is being reused,
891
+ // clean up memory now, so that we start with low usage.
892
+ // These regular GC calls take about 80-100 mS each, as opposed
893
+ // to forced GC calls, which occur randomly and can take several
894
+ // hundred mS.
895
+ app._collectGarbage();
896
+ }
892
897
  app.sendMetric('LambdaReused');
893
898
  } else {
894
899
  // This is the first use of this container, so set the
@@ -54,6 +54,54 @@ const testFixtures = path.resolve(process.cwd(), 'src/ssr/server/test_fixtures')
54
54
  const httpsAgent = new https.Agent({
55
55
  rejectUnauthorized: false
56
56
  });
57
+ function createServerWithGCSpy() {
58
+ const route = jest.fn((req, res) => {
59
+ res.send('<html/>');
60
+ });
61
+ const options = {
62
+ buildDir: testFixtures,
63
+ mobify: testPackageMobify,
64
+ sslFilePath: path.join(testFixtures, 'localhost.pem'),
65
+ quiet: true,
66
+ port: TEST_PORT,
67
+ fetchAgents: {
68
+ https: httpsAgent
69
+ }
70
+ };
71
+ const {
72
+ handler,
73
+ server,
74
+ app
75
+ } = RemoteServerFactory.createHandler(options, app => {
76
+ app.get('/*', route);
77
+ });
78
+ const collectGarbage = jest.spyOn(app, '_collectGarbage');
79
+ const sendMetric = jest.spyOn(app, 'sendMetric');
80
+ return {
81
+ route,
82
+ handler,
83
+ collectGarbage,
84
+ sendMetric,
85
+ server
86
+ };
87
+ }
88
+ function createApiGatewayEvent() {
89
+ // Set up a fake event and a fake context for the Lambda call
90
+ const event = createEvent('aws:apiGateway', {
91
+ path: '/',
92
+ body: undefined
93
+ });
94
+ if (event.queryStringParameters) {
95
+ delete event.queryStringParameters;
96
+ }
97
+ const context = AWSMockContext({
98
+ functionName: 'SSRTest'
99
+ });
100
+ return {
101
+ event,
102
+ context
103
+ };
104
+ }
57
105
  describe('SSRServer Lambda integration', () => {
58
106
  let savedEnvironment;
59
107
  let server;
@@ -329,42 +377,50 @@ describe('SSRServer Lambda integration', () => {
329
377
  X_HEADERS_TO_REMOVE_ORIGIN.forEach(key => expect(reqHeaders[key]).toBeUndefined());
330
378
  });
331
379
  });
332
- test('Lambda reuse behaviour', () => {
333
- const route = jest.fn((req, res) => {
334
- res.send('<html/>');
335
- });
336
- const options = {
337
- buildDir: testFixtures,
338
- mobify: testPackageMobify,
339
- sslFilePath: path.join(testFixtures, 'localhost.pem'),
340
- quiet: true,
341
- port: TEST_PORT,
342
- fetchAgents: {
343
- https: httpsAgent
344
- }
345
- };
380
+ test('Lambda reuse -- Default Behavior', () => {
346
381
  const {
347
- app,
382
+ route,
348
383
  handler,
349
- server: srv
350
- } = RemoteServerFactory.createHandler(options, app => {
351
- app.get('/*', route);
352
- });
353
- const collectGarbage = jest.spyOn(app, '_collectGarbage');
354
- const sendMetric = jest.spyOn(app, 'sendMetric');
355
- server = srv;
356
-
357
- // Set up a fake event and a fake context for the Lambda call
358
- const event = createEvent('aws:apiGateway', {
359
- path: '/',
360
- body: undefined
361
- });
362
- if (event.queryStringParameters) {
363
- delete event.queryStringParameters;
364
- }
365
- const context = AWSMockContext({
366
- functionName: 'SSRTest'
384
+ collectGarbage,
385
+ sendMetric,
386
+ new_server
387
+ } = createServerWithGCSpy();
388
+ const {
389
+ event,
390
+ context
391
+ } = createApiGatewayEvent();
392
+ server = new_server;
393
+ const call = event => new Promise(resolve => handler(event, context, (err, response) => resolve(response)));
394
+ return Promise.resolve().then(() => call(event)).then(response => {
395
+ // First request - Lambda container created
396
+ expect(response.statusCode).toBe(200);
397
+ expect(collectGarbage.mock.calls).toHaveLength(0);
398
+ expect(route.mock.calls).toHaveLength(1);
399
+ expect(sendMetric).toHaveBeenCalledWith('LambdaCreated');
400
+ expect(sendMetric).not.toHaveBeenCalledWith('LambdaReused');
401
+ }).then(() => call(event)).then(response => {
402
+ // Second call - Lambda container reused
403
+ expect(response.statusCode).toBe(200);
404
+ expect(collectGarbage.mock.calls).toHaveLength(0);
405
+ expect(route.mock.calls).toHaveLength(2);
406
+ expect(sendMetric).toHaveBeenCalledWith('LambdaCreated');
407
+ expect(sendMetric).toHaveBeenCalledWith('LambdaReused');
367
408
  });
409
+ });
410
+ test('Lambda reuse -- with Forced Garbage Collection Enabled', () => {
411
+ process.env.FORCE_GC = 'true';
412
+ const {
413
+ event,
414
+ context
415
+ } = createApiGatewayEvent();
416
+ const {
417
+ route,
418
+ handler,
419
+ collectGarbage,
420
+ sendMetric,
421
+ new_server
422
+ } = createServerWithGCSpy();
423
+ server = new_server;
368
424
  const call = event => new Promise(resolve => handler(event, context, (err, response) => resolve(response)));
369
425
  return Promise.resolve().then(() => call(event)).then(response => {
370
426
  // First request - Lambda container created
@@ -59,7 +59,11 @@ class MetricsSender {
59
59
  apiVersion: '2010-08-01',
60
60
  // The AWS_REGION variable is defined by the Lambda
61
61
  // environment.
62
- region: process.env.AWS_REGION || 'us-east-1'
62
+ region: process.env.AWS_REGION || 'us-east-1',
63
+ // Setting maxRetries to 0 will prevent the SDK from retrying.
64
+ // This is necessary because under high load, there will be backpressure
65
+ // on the Lambda function, and causing severe performance issues (400-500ms latency)
66
+ maxRetries: 0
63
67
  });
64
68
  }
65
69
  return this._CW;