Giter Club home page Giter Club logo

aio-lib-state's Introduction

Version Downloads/week Node.js CI License Codecov Coverage

Adobe I/O Lib State

A Node JavaScript abstraction on top of distributed/cloud DBs that exposes a simple state persistence API.

You can initialize the lib with your Adobe I/O Runtime (a.k.a OpenWhisk) credentials.

Alternatively, you can bring your own cloud db keys. As of now we only support Azure Cosmos.

Please note that currently you must be a customer of Adobe Developer App Builder to use this library. App Builder is a complete framework that enables enterprise developers to build and deploy custom web applications that extend Adobe Experience Cloud solutions and run on Adobe infrastructure.

Install

npm install @adobe/aio-lib-state

Use

  const stateLib = require('@adobe/aio-lib-state')

  // init when running in an Adobe I/O Runtime action (OpenWhisk) (uses env vars __OW_API_KEY and __OW_NAMESPACE automatically)
  const state = await stateLib.init()
  // or if you want to use your own cloud DB account (make sure your partition key path is /partitionKey)
  const state = await stateLib.init({ cosmos: { endpoint, masterKey, databaseId, containerId, partitionKey } })

  // get
  const res = await state.get('key') // res = { value, expiration }
  const value = res.value

  // put
  await state.put('key', 'value')
  await state.put('key', { anObject: 'value' }, { ttl: -1 }) // -1 for no expiry, defaults to 86400 (24 hours)

  // delete
  await state.delete('key')

Explore

goto API

Debug

set DEBUG=@adobe/aio-lib-state* to see debug logs.

Adobe I/O State Store Limitations (per user)

Apply when init with OW credentials (and not own cloud DB credentials):

  • Max state value size: 2MB
  • Max state key size: 1024 bytes
  • Max total state size: 10 GB
  • Token expiry (need to re-init after expiry): 1 hour
  • Non supported characters for state keys are: '/', '\', '?', '#'

Adobe I/O State Store Consistency Guarantees

Consistency across State Instances

Operations across multiple State instances (returned by stateLib.init()) are eventually consistent. For example, let's consider two state instances a and b initialized with the same credentials, then

const a = await state.init()
const b = await state.init()
await a.put('food', 'beans')
await b.put('food', 'carrots')
console.log(await a.get('food'))

might log either beans or carrots but eventually a.get('food') will always return carrots.

Operations within a single instance however are guaranteed to be strongly consistent.

Note that atomicity is ensured, i.e. a.get('food') will never return something like beacarronsts.

Adobe I/O Runtime considerations

State lib is expected to be used in Adobe I/O Runtime serverless actions. A new State instance can be created on every new invocation inside the main function of the serverless action as follows:

const State = require('@adobe/aio-sdk').State

function main (params) {
  const state = await State.init()
  // do operations on state

It's important to understand that in this case, on every invocation a new State instance is created, meaning that operations will be only eventually consistent across invocations but strongly consistent within an invocation.

Also note that reusing the State instance by storing it in a global variable outside of the main function would not ensure strong consistency across all invocations as the action could be executed in a separate Docker container.

Here is an example showcasing two invocations of the same action with an initial state { key: 'hello'}:

Invocation A Invocation B
state = State.init()
state.get(key) => returns hello
state.put(key, 'bonjour')
state.get(key) => returns bonjour
state = State.init()
state.get(key) => hello OR bonjour
state.put(key, 'bonjour')
state.get(key) => returns bonjour

Because of eventual consistency across State instances, in invocation B, the first state.get(key) might return an older value although invocation A has updated the value already.

Troubleshooting

"[StateLib:ERROR_INTERNAL] unknown error response from provider with status: unknown"

  • when using @adobe/aio-lib-state in an action bundled with webpack please make sure to turn off minification and enable resolving of es6 modules. Add the following lines to your webpack config:
  optimization: {
    minimize: false
  },
  resolve: {
    extensions: ['.js'],
    mainFields: ['main']
  }

Contributing

Contributions are welcomed! Read the Contributing Guide for more information.

Licensing

This project is licensed under the Apache V2 License. See LICENSE for more information.

aio-lib-state's People

Contributors

amulyakashyap09 avatar arjuncooliitr avatar dependabot[bot] avatar duynguyen avatar florind12 avatar greenkeeper[bot] avatar himavanth avatar justinedelson avatar meryllblanchet avatar michaelgoberling avatar moritzraho avatar purplecabbage avatar sandeep-paliwal avatar sarahxxu avatar shazron avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

aio-lib-state's Issues

StateLibError not defined error when using lib in typescript

Expected Behaviour

using lib in typescript application it will build without error

Actual Behaviour

Action Cleaning Done
node_modules/@adobe/aio-lib-state/types.d.ts:79:25 - error TS2552: Cannot find name 'StateLibError'. Did you mean 'StateLibErrors'?

79 ERROR_BAD_ARGUMENT: StateLibError;
~~~~~~~~~~~~~

node_modules/@adobe/aio-lib-state/types.d.ts:80:24 - error TS2552: Cannot find name 'StateLibError'. Did you mean 'StateLibErrors'?

80 ERROR_BAD_REQUEST: StateLibError;
~~~~~~~~~~~~~

node_modules/@adobe/aio-lib-state/types.d.ts:81:28 - error TS2552: Cannot find name 'StateLibError'. Did you mean 'StateLibErrors'?

81 ERROR_NOT_IMPLEMENTED: StateLibError;
~~~~~~~~~~~~~

node_modules/@adobe/aio-lib-state/types.d.ts:82:30 - error TS2552: Cannot find name 'StateLibError'. Did you mean 'StateLibErrors'?

82 ERROR_PAYLOAD_TOO_LARGE: StateLibError;
~~~~~~~~~~~~~

node_modules/@adobe/aio-lib-state/types.d.ts:83:28 - error TS2552: Cannot find name 'StateLibError'. Did you mean 'StateLibErrors'?

83 ERROR_BAD_CREDENTIALS: StateLibError;
~~~~~~~~~~~~~

node_modules/@adobe/aio-lib-state/types.d.ts:84:21 - error TS2552: Cannot find name 'StateLibError'. Did you mean 'StateLibErrors'?

84 ERROR_INTERNAL: StateLibError;

Build fails

Reproduce Scenario (including but not limited to)

Steps to Reproduce

typescript app and try to use the state lib in a function.
"typescript": "^4.6.4"
For the record this worked error free over a year ago.

Platform and Version

System:
OS: Windows 10 10.0.22000
CPU: (20) x64 Intel(R) Xeon(R) W-2255 CPU @ 3.70GHz
Memory: 90.87 GB / 127.69 GB
Binaries:
Node: 14.19.1
Yarn: 1.22.18
npm: 6.14.16
Virtualization:
Docker: Not Found
npmGlobalPackages:
@adobe/aio-cli: Not Found

Proxies:
http: (not set)
https: (not set)
CLI plugins:
core:
@adobe/aio-cli 8.3.0
@adobe/aio-cli-plugin-app 8.6.1
@adobe/aio-cli-plugin-auth 2.6.0
@adobe/aio-cli-plugin-certificate 0.3.1
@adobe/aio-cli-plugin-config 3.0.1
@adobe/aio-cli-plugin-console 3.4.2
@adobe/aio-cli-plugin-events 1.1.6
@adobe/aio-cli-plugin-info 2.1.0
@adobe/aio-cli-plugin-runtime 5.4.0
@oclif/plugin-autocomplete 0.3.0
@oclif/plugin-help 3.3.1
@oclif/plugin-not-found 2.3.1
@oclif/plugin-plugins 1.10.11
@oclif/plugin-warn-if-update-available 1.7.3
user:
link:

Sample Code that illustrates the problem

tsconfig.json
`{
"compilerOptions": {
/* Basic Options */
"module": "commonjs", /Specify module code generation: "None", "CommonJS", "AMD", "System", "UMD", "ES6", "ES2015" or "ESNext". Only "AMD" and "System" can be used in conjunction with --outFile. "ES6" and "ES2015" values may be used when targeting "ES5" or lower./
"target": "es5", /Specify ECMAScript target version: "ES3" (default),"ES5","ES6"/"ES2015","ES2016","ES2017","ES2018","ES2019","ES2020","ESNext"/
//"lib": [ "es2015", "dom" ], /*List of library files to be included in the compilation. see https://www.typescriptlang.org/docs/handbook/compiler-options.html /
//"removeComments": true,
//"resolveJsonModule": true,
//"esModuleInterop": true,
//"typeRoots" : [
// "./node_modules/@types/",
// "./typings/"
//],
// "lib": [], /
Specify library files to be included in the compilation. /
"allowJs": false, /
Allow javascript files to be compiled. /
"checkJs": false, /
Report errors in .js files. /
// "jsx": "preserve", /
Specify JSX code generation: 'preserve', 'react-native', or 'react'. /
"declaration": false, /
Generates corresponding '.d.ts' file. /
// "declarationMap": true, /
Generates a sourcemap for each corresponding '.d.ts' file. /
"sourceMap": false, /
Generates corresponding '.map' file. /
// "outFile": "./", /
Concatenate and emit output to single file. /
"outDir": "actions", /
Redirect output structure to the directory. /
// "rootDir": "./", /
Specify the root directory of input files. Use to control the output directory structure with --outDir. /
// "composite": true, /
Enable project compilation /
// "removeComments": true, /
Do not emit comments to output. /
// "noEmit": true, /
Do not emit outputs. /
//"importHelpers": true, /
Import emit helpers from 'tslib'. /
// "downlevelIteration": true, /
Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. /
// "isolatedModules": true, /
Transpile each file as a separate module (similar to 'ts.transpileModule'). */

    /* Strict Type-Checking Options */
    //"strict": true,                           /* Enable all strict type-checking options. */
    "noImplicitAny": false,                 /* Raise error on expressions and declarations with an implied 'any' type. */
    //"strictNullChecks": false,              /* Enable strict null checks. */
    // "strictFunctionTypes": true,           /* Enable strict checking of function types. */
    // "strictPropertyInitialization": true,  /* Enable strict checking of property initialization in classes. */
    // "noImplicitThis": true,                /* Raise error on 'this' expressions with an implied 'any' type. */
    // "alwaysStrict": true,                  /* Parse in strict mode and emit "use strict" for each source file. */
    
    /* Additional Checks */
    // "noUnusedLocals": true,                /* Report errors on unused locals. */
    // "noUnusedParameters": true,            /* Report errors on unused parameters. */
    // "noImplicitReturns": true,             /* Report error when not all code paths in function return a value. */
    // "noFallthroughCasesInSwitch": true,    /* Report errors for fallthrough cases in switch statement. */
    
    /* Module Resolution Options */
    "moduleResolution": "node",            /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
    // "baseUrl": "./",                       /* Base directory to resolve non-absolute module names. */
    // "paths": {},                           /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
    // "rootDirs": [],                        /* List of root folders whose combined content represents the structure of the project at runtime. */
    // "typeRoots": [],                       /* List of folders to include type definitions from. */
    // "types": ["jest", "node"],                           /* Type declaration files to be included in compilation. */
    // "allowSyntheticDefaultImports": true,  /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
    "esModuleInterop": true                   /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
    // "preserveSymlinks": true,              /* Do not resolve the real path of symlinks. */
    
    /* Source Map Options */
    // "sourceRoot": "",                      /* Specify the location where debugger should locate TypeScript files instead of source locations. */
    // "mapRoot": "",                         /* Specify the location where debugger should locate map files instead of generated locations. */
    // "inlineSourceMap": true,               /* Emit a single file with source maps instead of having a separate file. */
    // "inlineSources": true,                 /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
    
    /* Experimental Options */
    // "experimentalDecorators": true,        /* Enables experimental support for ES7 decorators. */
    // "emitDecoratorMetadata": true,         /* Enables experimental support for emitting type metadata for decorators. */
},
"include": [
    "./actions-src/**/*"
],
"exclude": [
    "dev-keys"
]

}`

Is this a problem or do I not fully understand some type of definition rule or do i have a TypeScript check on I dont need.
image (1)

Correct configuration of bring-your-own cosmosdb account

If an SDK user wants to use his/her own cosmosDB account, the SDK is initiated as below:

const state = await stateLib.init({ cosmos: { endpoint, masterKey, databaseId, containerId, partitionKey } })

The cosmos DB, container and partition have to be set up correctly. Specifically, the key path of the partition must be /partitionKey so that getting value would work. As a to-do task, we should either:

  1. document the pre-reqs clearly in README
  2. make the key path configurable so that user can update it when necessary

Related discussion: https://experienceleaguecommunities.adobe.com/t5/project-firefly-questions/access-to-own-storage-using-aio-lib-state-and-aio-lib-action/qaq-p/378249/

Very long init times on cold start

While using state in an action to cache a token for reuse, I noticed that initializing the state lib via State.init() sometimes takes a very long time on cold starts.

The time it takes to init ranges from a few seconds up until 30s worst case so far! Following an excerpt of cold start activations that show long init times. Of course, the time it takes for the cold start and some internal operations need to be discounted (~2-3s) but the major part is taken up by State.init().

Throws firewall error when using invalid characters for keys

Actual Behaviour

  • await state.get("?test", "test")
  • Attempt to run code
  • State lib throws Firewall error:
{
  "error": "[StateLib:ERROR_FIREWALL] cannot access underlying DB provider because your IP is blocked by a firewall, please make sure to run in an Adobe I/O Runtime action"
}

Expected Behaviour

  • await state.get("?test", "test")
  • Attempt to run code
  • State lib throws error about invalid key characters

Related

The library doesn't throw an error on await state.put("?test"), should it?

An in-range update of @azure/cosmos is breaking the build 🚨

The dependency @azure/cosmos was updated from 3.4.0 to 3.4.1.

🚨 View failing branch.

This version is covered by your current version range and after updating it in your project the build failed.

@azure/cosmos is a direct dependency of this project, and it is very likely causing it to break. If other packages depend on yours, this update is probably also breaking those in turn.

Status Details

FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

Handle 429s errors

Expected Behaviour

429s from CosmosDB might arise if RU/s are consumed. State lib should wrap the error to hide the internal CosmosDB error and let the user catch the specific error based on a documented error code.
An optional retry mechanism could be directly implemented in state lib.

Actual Behaviour

The error is unknown to state lib, hence it is not wrapped and the internal cosmosDB error is shown

"_internal": {
      "stack": "Error: Message: {\"Errors\":[\"Request rate is large. More Request Units may be needed, so no changes were made. Please retry this request later. Learn more: http://aka.ms/cosmosdb-error-429\"]}\r\nActivityId:
[..]

If the user wants to implement an error mechanism he has to parse the private _internal field of the error

Broken auto completion in vscode on instance object

const state = await stateLib.init() // => autocompletes
state. // => doesn't autocomplete

vscode's intellisense uses typescript types which seem to be compatible/inferred from our JSDoc. But there might be some sort of conflict.

optimize using in-memory caching

To reduce costs and enhance performance use an in-memory cache in front of the provider.

  • read: check in memory cache -> miss -> check remote db

extend strong consistency to the process level instead of instance level

Currently strong consistency is only supported for operations executed within one state instance (i.e. result of stateLib.init()). This behavior is guaranteed by Cosmos DB session consistency model.

This can be easily extended to support strong consistency across instances within the same process by storing the cosmos session id into a static variable when initializing the first instance and reusing the same id for subsequent instances.

Explore reducing probability of hitting rate limit of cosmos metadata

Too many requests to aio-tvm/tvm/azure-cosmos to the tune of 5k requests per sec hit metadata rate limit of cosmos db.

[@adobe/aio-tvm] error: Message: {"Errors":["The request did not complete due to a high rate of metadata requests. Increasing request units will have no impact and is not recommended. Please retry the request. https:\/\/aka.ms\/CosmosDB\/sql\/errors\/metadata-429"]}

We should explore reusing the cosmos client and hence reducing number of initializations which could be one of the causes for metadata rate limit.
Ref https://docs.microsoft.com/en-us/azure/cosmos-db/sql/troubleshoot-request-rate-too-large#rate-limiting-on-metadata-requests
The solution should take into account the concurrency of TVM actions.

Expected Behaviour

Actual Behaviour

Reproduce Scenario (including but not limited to)

Steps to Reproduce

Platform and Version

Sample Code that illustrates the problem

Logs taken while reproducing problem

Document consistency model

  • how does the state sdk behave in case of rd after write?

    • within an instance?
    • across action invocations?
    • across multiple actions?
  • what happens in case of wr after wr?

    • do we have atomicity ? e.g. put(key, 'hello'), put(key, 'yolo'), read(key) always returns 'hello' or 'yolo' and never smthg like 'helyololo' (Yes it's the case)

state.get bad performance under cold and warm starts

See investigations under #63

Expected Behaviour

Under a cold start, a state.get will take approx less than a second.

Actual Behaviour

Under a cold start, a state.get will take approx 1800ms.

Possible issues

On a warm start, a state.get will still take approx 450ms

The @azure/cosmos promise that is resolved here, takes up 99.9% of the time for a state.get call:

  1. const response = await _wrap(this._cosmos.container.item(key, this._cosmos.partitionKey).read(), { key })
  2. https://github.com/Azure/azure-sdk-for-js/blob/1a77eb5fae58a3bb7ced6610dbdf9afe500bab60/sdk/cosmosdb/cosmos/src/client/Container/Container.ts#L109
  3. https://github.com/Azure/azure-sdk-for-js/blob/1a77eb5fae58a3bb7ced6610dbdf9afe500bab60/sdk/cosmosdb/cosmos/src/client/Item/Item.ts#L73

I don't think there can be any more code optimizations possible here since it seems the bottleneck is the CosmosDB read call. The only possible solutions I can see are:

  1. (network) perhaps the data is read from a far away Azure region increasing network latency?
  2. (server) perhaps there is a configuration setting in Azure that will help with CosmosDB NoSQL reads? (partitioning key strategies?)
  3. (client) perhaps there is a more optimal way to use the @azure/cosmos SDK

[aio-lib-state] retrieving value via State.get takes more than 60s under load

During a load test against one of our actions where we're using State from aio-lib-state to cache a token for reuse, we observed that on very rare occasions, the state.get call takes just a little over 60s to respond with the requested value. This leads to developer errors due to the action exceeding the default timeout of 60s.

Here are a few activation IDs for which this was observed:

ad65d2b56866448aa5d2b56866848ab4
ea2d8cee79ca4841ad8cee79cad841c2
61d28c62fad0444a928c62fad0d44a1f

Feature request: add api to query/list keys

The following code can be used to get a list of all keys, but it exposes the inner workings of the state-lib. It would be nice to build this into the api so it is just an opaque-box.

potential api

async state.listKeys(continuationToken:string = '')
returning {
  keys: [],
  continuationToken: ''
}

current workaround

const stateLib = require('@adobe/aio-lib-state')
const state = await stateLib.init()
const queryPlan = state._cosmos.container.items.query(`SELECT c.id,c.ttl,c._ts from c where c.partitionKey='${state._cosmos.partitionKey}'`, {
  initialHeaders: {
    'x-ms-documentdb-partitionkey': `["${state._cosmos.partitionKey}"]`
  },
  continuationToken: params.continuationToken
})
const queryRes = await queryPlan.fetchNext()
const res = queryRes.resources.map(x => ({ key: x.id, expiration: getExpiration(x.ttl, x._ts) }))
const response = {
  statusCode: 200,
  // todo check the continuation token
  body: {
    message: 'success',
    keys: res,
    hasMoreResults: queryRes.hasMoreResults,
    continuationToken: queryPlan.continuationToken
  } // default is 24hours
}

Abstract StateStore class methods do not need to be `async`

Expected Behaviour

Works as described.

Actual Behaviour

Works as described, with an extra Promise in the chain.

Reproduce Scenario (including but not limited to)

N/A

Steps to Reproduce

N/A

Platform and Version

N/A

Sample Code that illustrates the problem

N/A

Logs taken while reproducing problem

N/A

Invalid key name leads to obscure error message

Expected Behaviour

Error: Illegal characters ['/', '\\', '?', '#'] cannot be used in resourceId

is reported in the logs.

Actual Behaviour

[StateLib:ERROR_INTERNAL] unknown error response from provider with status: unknown

is reported in the logs.

Reproduce Scenario (including but not limited to)

try to get/put using a key such as "abc/def"

Steps to Reproduce

Platform and Version

Sample Code that illustrates the problem

Logs taken while reproducing problem

2021-06-30T12:27:31.615Z       stdout: 2021-06-30T12:27:31.615Z @adobe/aio-lib-state:debug got internal error with status undefined: Illegal characters ['/', '\', '?', '#'] cannot be used in resourceId
2021-06-30T12:27:31.632Z       stdout: 2021-06-30T12:27:31.632Z @adobe/aio-lib-state:error {
  "sdk": "StateLib",
  "sdkDetails": {
    "key": "titan/task/update/adoberm",
    "_internal": {
      "stack": "Error: Illegal characters ['/', '\\', '?', '#'] cannot be used in resourceId\n    at validateResourceId (/nodejsAction/4tfYwswP/index.js:56177:15)\n    at createDocumentUri (/nodejsAction/4tfYwswP/index.js:56325:5)\n    at Item.get url [as url] (/nodejsAction/4tfYwswP/index.js:59961:16)\n    at Item.<anonymous> (/nodejsAction/4tfYwswP/index.js:59993:47)\n    at Generator.next (<anonymous>)\n    at /nodejsAction/4tfYwswP/index.js:178946:71\n    at new Promise (<anonymous>)\n    at Module.__awaiter (/nodejsAction/4tfYwswP/index.js:178942:12)\n    at Item.read (/nodejsAction/4tfYwswP/index.js:59988:22)\n    at CosmosStateStore._get (/nodejsAction/4tfYwswP/index.js:38789:94)",
      "message": "Illegal characters ['/', '\\', '?', '#'] cannot be used in resourceId"
    }
  },
  "code": "ERROR_INTERNAL",
  "message": "[StateLib:ERROR_INTERNAL] unknown error response from provider with status: unknown",
  "stacktrace": "StateLibError: [StateLib:ERROR_INTERNAL] unknown error response from provider with status: unknown\n    at new <anonymous> (/nodejsAction/4tfYwswP/index.js:20660:9)\n    at _wrap (/nodejsAction/4tfYwswP/index.js:38705:17)"
}

put doesn't throw validation error if ttl is a number as string

Expected Behaviour

When trying to put new data with a ttl being a number as a string, I'd expect a validation error to be thrown.

Actual Behaviour

No validation error is thrown, and a generic error message with no further details is thrown.
According to @shazron, javascript coerces the string to a number but only for validation purposes.

Reproduce Scenario (including but not limited to)

Steps to Reproduce

  • initialize the state-lib
  • put data with a ttl of '300' (string)

Platform and Version

aio-lib-state 1.1.1
nodeJS 14

Sample Code that illustrates the problem

const State = require('@adobe/aio-lib-state');
const state = await State.init();
await state.put('key', 'value', { ttl: '300' });

Logs taken while reproducing problem

StateLibError: [StateLib:ERROR_INTERNAL] unknown error response from provider with status: 400

Firewall restrictions are reported as bad credentials

Expected Behaviour

When I use aio-lib-state from outside my company's firewall, Cosmos DB reports an error Request originated from client IP x.x.x.x This is blocked by your Cosmos DB account firewall settings. This circumstance should be somehow reflected in the exception returned from aio-lib-state.

Actual Behaviour

I'm getting an exception with message [StateLib:ERROR_BAD_CREDENTIALS] cannot access underlying DB provider. This gives the impression that the credentials are bad and leads me up the wrong track.

Reproduce Scenario (including but not limited to)

Outside company firewall that has access rules.

Steps to Reproduce

Run code locally that uses aio-lib-state.

Platform and Version

macOS 10.15.3, node v10.18.0

Sample Code that illustrates the problem

const stateLib = require('@adobe/aio-lib-state');
function main(params) {
  const state = await stateLib.init();
  const obj = await state.get('foo');
}

Logs taken while reproducing problem

Large overhead from State initialization during action cold start

In I/O Runtime, the first activation of an action is a cold start (which means the action code is downloaded to the docker container, npm modules are loaded into memory and library initialization are done).
In my test, the normal cold start time of a bare minimal action (only return a json with some texts) is approx. 1.5 to 2 seconds.
However, the exact same code containing state.init to initialize the State SDK and state.get to retrieve some value from State would double this overhead during cold start, i.e. 3 to 4 seconds.
Once the action container is warm, subsequent activations take less than 200ms, which means the actual retrieval state.get does not take much time. That leads to state.init being the biggest suspect of the huge overhead of up to 2s as described above.

Action code that resulted in approx. 4s cold start:

const { State } = require('@adobe/aio-sdk')

async function main (params) {
    const state = await State.init()
    const valueObj = await state.get(params.key)
    let value = null
    if (valueObj){
      value = valueObj.value
    }

    const response = {
      statusCode: 200,
      body: {
        key: params.key,
        value
      }
    }
    return response
}

exports.main = main

Same action code, without the use of State, resulted in approx. 2s cold start:

const { State } = require('@adobe/aio-sdk')

async function main (params) {
    const value = 'Hello'

    const response = {
      statusCode: 200,
      body: {
        key: params.key,
        value
      }
    }
    return response
}

exports.main = main

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.