Edgio
Edgio

Limits and Caveats

Edgio Platform Limits

This guide describes caveats and limits of Edgio platform as applied to all projects running on it.

Legend

  • Kb stands for kilobytes and means 1,024 bytes (2^10 bytes)
  • Mb stands for megabytes and means 1,024 kilobytes (2^20 bytes)
  • Gb stands for gigabytes and means 1,024 megabytes (2^30 bytes)

Request and Response Limits

TypeLimitDescription
Response time from origin server60 secondsThe maximum number of seconds that Edgio will wait for a response from an origin server (e.g., your web server). The response for a request that exceeds this limit is a 531 Project Upstream Connection Error.

Requests that exceed this limit should return a 536 Project HTTP Response Timeout. We will update our service to return this status code instead of a 531 Project Upstream Connection Error response in the near future.
Response body size from static2GbThe maximum size of a response body of Edgio static assets.
Response body size from custom origin2GbThe maximum size of a response body from a custom origin.
Response body size from Edgio serverless6MbThe maximum size of a response body from Edgio serverless.
Path and query string size8KbThe maximum bytes (not characters) that Edgio will accept in path and query string.
Cookie size32KbThe maximum bytes that Edgio will accept in request or response cookies.
HTTP header size64KbThe maximum bytes that Edgio will accept in request or response HTTP headers.
HTTP header count70The maximum number of developer-controlled headers Edgio will accept in HTTP request or response. Exceeding this will result in 542 status code.
Scheduling timeout60 secondsThe number of seconds Edgio will try to schedule a request processing before timing out. Exceeding this will result in 541 status code.
Worker timeout20 secondsThe number of seconds Edgio will wait for project code to process the request before timing out. Exceeding this will result in 539 status code.
Prerender concurrency200
Total number of prerendered requests25,000 per deployment
Maximum number of nested requests3“Nested” means an Edgio site is the upstream of itself or of another Edgio site. Exceeding this will result in 538 status code.

Access Logs

ValueLimitDescription
SizeUnlimitedAll access logs will always be logged.
Time2 hoursThe minimum time that Edgio guarantees that access logs will be available for reading.

Prohibited Headers

The following is a list of headers that cannot be modified by your project code. These values are immutable and can only be set by the Edgio platform.

  • x-0-platform
  • x-0-version
  • x-0-t
  • x-0-components
  • x-0-status
  • host
  • x-request-id
  • content-length
  • via

Serverless Bundle Size

Edgio has a serverless bundle limit for your project of 50 MB (250 MB uncompressed). If your deployment to Edgio fails due to exceeding the bundle limit, you will see the following error message:

12022-08-08T13:47:13Z - internal error - Error in xdn-deploy-lambda: Your production build exceeds the maximum allowed size of 50 MB (compressed) / 250 MB (uncompressed).
2The current size is 51.19 MB (compressed).
3Please ensure that list of dependencies in package.json contains only those packages that are needed at runtime.
4Move all build-time dependencies such as webpack, babel, etc... to devDependencies, rerun npm | yarn install, and try to deploy again.

Following are the possible fixes that would help you reduce serverless bundle size by better engineering. If none of these does it, feel free to raise an issue on Edgio Forums.

Possible Fix [1]: Segregating devDependencies from dependencies

Typically, this is due to node_modules marked as dependencies when they are more appropriate in devDependencies within the package.json file. Modules marked as dependencies will be included in the serverless bundle. Dev-only modules such as babel, jest, webpack, etc. should be moved to devDependencies as shown:

Diff
1"dependencies": {
2 "@nuxtjs/sitemap": "2.4.0",
3 "@nuxt/core": "2.15.7"
4- "babel": "7.12.7",
5- "jest": "28.1.3"
6+ },
7+ "devDependencies": {
8+ "babel": "7.12.7",
9+ "jest": "28.1.3"
10}

Possible Fix [2]: Segregating assets from serverless bundle

Additionally, this can be related to assets (such as fonts or images) that are imported into your project code. These resources are typically better referenced as static assets which are stored outside of the serverless bundle.

You can remedy this by creating a public directory in the root of your project. Move all of your font and image assets to this path. Then, create a route in routes.js to serve those requests as static assets using the following as an example:

JavaScript
1router.get('/assets/:path*', ({ serveStatic }) => {
2 serveStatic('public/:path*')
3})

Now, you can update your code references from importing the assets to referencing the static path, such as:

Diff
1- import myImage from 'public/images/Image1.png'
2...
3- <div><img src={myImage}/></div>
4+ <div><img src="/assets/images/Image1.png"/></div>

Possible Fix [3]: Computing which node_modules be included in the serverless bundle

It might be possible, that Possible Fix [1] reduces your serverless bundle size, but not reduce it to less than 50 MB (250 MB Uncompresssed). Another way to identify which dependencies would be required in the runtime is to use @vercel/nft package (a “Node.js dependency tracing utility”).

Step 1. Install @vercel/nft as devDependency:

Bash
1npm i -D @vercel/nft

Step 2. Create a file named setNodeModules.js in the root directory of your project with the following code:

JavaScript
1const fs = require('fs')
2const { nodeFileTrace } = require('@vercel/nft')
3
4const setNodeModules = async () => {
5 // Enter an entry point to the app, for example in Nuxt(2), the whole app inside core.js
6 const files = ['./node_modules/@nuxt/core/dist/core.js']
7 // Compute file trace
8 const { fileList } = await nodeFileTrace(files)
9 // Store set of packages
10 let packages = {}
11 fileList.forEach((i) => {
12 if (i.includes('node_modules/')) {
13 let temp = i.replace('node_modules/', '')
14 temp = temp.substring(0, temp.indexOf('/'))
15 packages[`node_modules/${temp}`] = true
16 } else {
17 packages[i] = true
18 }
19 })
20 // Sort the set of packages to maintain differences with git
21 fs.writeFileSync(
22 './getNodeModules.js',
23 `module.exports=${JSON.stringify(
24 Object.keys(packages)
25 .sort()
26 .reduce((obj, key) => {
27 obj[key] = packages[key]
28 return obj
29 }, {})
30 )}`
31 )
32}
33
34setNodeModules()

Step 3. Change your existing package.json to have node setNodeModules.js before each command as follows:

Diff
1- "layer0:dev": "layer0 dev",
2- "layer0:build": "layer0 build",
3- "layer0:deploy": "layer0 deploy"
4
5+ "layer0:dev": "node setNodeModules.js && layer0 dev",
6+ "layer0:build": "node setNodeModules.js && layer0 build",
7+ "layer0:deploy": "node setNodeModules.js && layer0 deploy"

Step 4. Change your layer0.config.js to have:

JavaScript
1// https://docs.layer0.co/guides/layer0_config
2module.exports = {
3 includeFiles: require('./getNodeModules'),
4}

Edgio Platform Caveats

NodeJS native extensions

In a lof of scenarios, NodeJS native extensions might be required to perform specific tasks related to your application. For example, you might need to use OpenCV to perform some checks on an image before making it publicly available. Or you might need to use extensions like node-microtime for finer-grained performance analysis.

When Edgio bundles your application for deployment, we also do some “tree-shaking” to remove unnecessary files in your build. This makes the bundle size smaller and more efficient to load on our serverless platform during a cold-start. But it could have unintended consequences where we might strip away native extension binaries required for your application to function.

If that is the case, you might encounter an error like the following when trying to use modules that depend on the native binaries.

1Error: No native build was found for runtime=node abi=83 platform=linuxglibc arch=x64
2at Function.load.path (/var/task/node_modules/microtime/node_modules/node-gyp-build/index.js:59:9)
3at load (/var/task/node_modules/microtime/node_modules/node-gyp-build/index.js:19:30)
4at Object.<anonymous> (/var/task/node_modules/microtime/index.js:1:43)
5at Module._compile (internal/modules/cjs/loader.js:1085:14)
6at Object.Module._extensions..js (internal/modules/cjs/loader.js:1114:10)
7at Module.load (internal/modules/cjs/loader.js:950:32)
8at Function.Module._load (internal/modules/cjs/loader.js:790:12)
9at Module.require (internal/modules/cjs/loader.js:974:19)
10at require (internal/modules/cjs/helpers.js:101:18)
11at Object.<anonymous> (/var/task/node_modules/broadcast-channel/dist/es5node/methods/node.js:57:41)

To fix this issue, you need to instruct Edgio to include the binary files that your application requires. This can be done by using the includeFiles property in layer0.config.js like so:

JavaScript
1includeFiles: {
2 'node_modules/microtime/**/*': true,
3},

Or you could choose to bundle everything in the packages listed in the dependencies property of package.json by using includeNodeModules property.

Readonly filesystem in serverless runtime

Web developers often use the filesystem as a temporary data source for their applications. That includes creating and/or manipulating files based on user requests. For example, storing user uploaded files locally and stripping metadata before proceeding. But this can open up security vulnerabilities where a bug in the application can be used to modify the application itself.

So, as a best practice Edgio App Platform does not allow you to change the content of application files on the filesystem during runtime. If you need to modify an application file, you must make those changes locally and make a new deployment. This limits the attack surface of your potential application vulnerabilities. It also allows us to make your application more distributed and resilient to outages. Edgio takes your application code and deploys it to multiple regions with a read-only filesystem. This way, if the primary availability zone or region is unavailable, your application will still be accessible from another region.

Edgio App Platform runs your application in /var/task directory. If you attempt to write a file in that directory, you may come across an error like the following:

1EROFS: read-only file system, open '/var/task/temp-upload.jpg'

To resolve issues like this you can use “tmp” directory to store any temporary files. But this directory might be different on you local environment vs Edgio serverless runtime. So, following is a good way to write code that will work on your local machine as well as Edgio serverless runtime.

JavaScript
1import { tmpdir } from 'os';
2import * as path from 'path';
3const tmpFilePath = path.join(tmpdir(), 'temp-upload.jpg');

Another thing to keep in mind is that “tmp” directory is ephemeral, meaning that it gets reset/recycled. If you store a file in “tmp”, it most likely won’t be available in the next request. That’s why you’ll need to use external services to store permanent file storage. These external services can be Amazon S3, Google Cloud Storage, or any other storage.