Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 11 additions & 36 deletions packages/pwa-kit-runtime/src/ssr/server/build-remote-server.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ import {hybridProxy} from '../../utils/ssr-server/hybrid-proxy'
import {convertExpressRouteToRegex} from '../../utils/ssr-server/convert-express-route'
import {ServerlessAdapter} from '@h4ad/serverless-adapter'
import {DefaultHandler} from '@h4ad/serverless-adapter/lib/handlers/default'
import {CallbackResolver} from '@h4ad/serverless-adapter/lib/resolvers/callback'
import {PromiseResolver} from '@h4ad/serverless-adapter/lib/resolvers/promise'
import {ApiGatewayV1Adapter} from '@h4ad/serverless-adapter/lib/adapters/aws'
import {ExpressFramework} from '@h4ad/serverless-adapter/lib/frameworks/express'
import {is as typeis} from 'type-is'
Expand Down Expand Up @@ -1275,7 +1275,7 @@ export const RemoteServerFactory = {
})
.setFramework(new ExpressFramework())
.setHandler(new DefaultHandler())
.setResolver(new CallbackResolver())
.setResolver(new PromiseResolver())
.addAdapter(
new ApiGatewayV1Adapter({
// Preserve the original aws-serverless-express behavior
Expand All @@ -1285,7 +1285,7 @@ export const RemoteServerFactory = {
)
.build()

const handler = (event, context, callback) => {
const handler = async (event, context) => {
// encode non ASCII request headers
if (options?.encodeNonAsciiHttpHeaders) {
Object.keys(event.headers).forEach((key) => {
Expand All @@ -1304,24 +1304,6 @@ export const RemoteServerFactory = {
})
}

// We don't want to wait for an empty event loop once the response
// has been sent. Setting this to false will "send the response
// right away when the callback executes", but any pending events
// may be executed if the Lambda container is then reused for
// another invocation (which we expect will happen under all
// but very low load). This means two things:
// 1. Any code that we have *after* the callback MAY be executed
// if the Lambda container is reused, but there's no guarantee
// it will be.
// 2. There is no way to have code do cleanup work (such as sending
// metrics) after the response is sent to the browser. We have
// to accept that doing such work delays the response.
// It would be good if we could set this to true and do work like sending
// metrics after calling the callback, but that doesn't work - API Gateway
// will wait for the Lambda invocation to complete before sending
// the response to the browser.
context.callbackWaitsForEmptyEventLoop = false

if (lambdaContainerReused) {
const forceGarbageCollection = process.env.FORCE_GC
if (forceGarbageCollection && forceGarbageCollection.toLowerCase() === 'true') {
Expand All @@ -1340,21 +1322,14 @@ export const RemoteServerFactory = {
app.sendMetric('LambdaCreated')
}

const managedCallback = (err, response) => {
return (
app._requestMonitor
._waitForResponses()
.then(() => app.metrics.flush())
// Now call the Lambda callback to complete the response
.then(() => callback(err, processLambdaResponse(response, event)))
// DON'T add any then() handlers here, after the callback.
// They won't be called after the response is sent, but they
// *might* be called if the Lambda container running this code
// is reused, which can lead to odd and unpredictable
// behaviour.
)
}
return serverlessAdapterHandler(event, context, managedCallback)
const response = await serverlessAdapterHandler(event, context)

// Lambda returns the response when the Promise resolves, so
// we await critical async work before returning.
await app._requestMonitor._waitForResponses()
await app.metrics.flush()

return processLambdaResponse(response, event)
}
// Upgrading to serverless-adapter removes the server property
// return a null server to maintain backwards compatibility
Expand Down
2 changes: 1 addition & 1 deletion packages/template-mrt-reference-app/config/default.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ module.exports = {
'config/default.js'
],
ssrParameters: {
ssrFunctionNodeVersion: '22.x',
ssrFunctionNodeVersion: '24.x',
proxyConfigs: [
{
host: 'httpbin.org',
Expand Down
2 changes: 1 addition & 1 deletion packages/template-mrt-reference-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
"mobify": {
"ssrEnabled": true,
"ssrParameters": {
"ssrFunctionNodeVersion": "22.x",
"ssrFunctionNodeVersion": "24.x",
"proxyConfigs": [
{
"host": "httpbin.org",
Expand Down
2 changes: 1 addition & 1 deletion packages/template-retail-react-app/config/default.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ module.exports = {
'**/*.json'
],
ssrParameters: {
ssrFunctionNodeVersion: '22.x',
ssrFunctionNodeVersion: '24.x',
proxyConfigs: [
{
host: 'kv7kzm78.api.commercecloud.salesforce.com',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ module.exports = {
],
// Additional parameters that configure Express app behavior.
ssrParameters: {
ssrFunctionNodeVersion: '22.x',
ssrFunctionNodeVersion: '24.x',
proxyConfigs: [
{
host: 'localhost:8888',
Expand Down
Loading