-
Notifications
You must be signed in to change notification settings - Fork 72
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Enhance processing and add caching #1025
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Took an initial look (was curious :p ). I like the vm module from node 💪
@@ -23,5 +23,6 @@ describe('constants', () => { | |||
expect(constants.PRIORITY_FEE).toEqual(3120000000); | |||
expect(constants.BASE_FEE_MULTIPLIER).toEqual(2); | |||
expect(constants.MAXIMUM_ONCHAIN_ERROR_LENGTH).toEqual(100); | |||
expect(constants.PROCESSING_TIMEOUT).toEqual(10_000); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But isn't 10s default too much? Also this timer affects the Airnode cycle and those are not configurable as of now (I think we should discuss this).
ahahahahaa |
Co-authored-by: Emanuel Tesař <[email protected]>
The current OAuth2 snippet I'm using (which I can post on Slack if you're curious), takes around 2s to resolve a token (when it needs to refresh the token, often an existing token will be available from the cache in which case it will be much faster, hence why caching is here). But as above I think the timeout should be exposed in |
…ao/airnode into enhance-processing-and-add-caching
I've kept the timeout on |
This is now the total timeout and it shouldn't affect anything else? I think the total parent cycle has 30 seconds of execution time? |
This is still pending testing on cloud. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks mostly good to me but I left some comments.
Co-authored-by: Emanuel Tesař <[email protected]>
Co-authored-by: Emanuel Tesař <[email protected]>
Co-authored-by: Emanuel Tesař <[email protected]>
Co-authored-by: Emanuel Tesař <[email protected]>
Co-authored-by: Emanuel Tesař <[email protected]>
…essing-and-add-caching
Hopefully I can test this on cloud today. |
Works on cloud with the most recent commit. I tried a few different ways of getting this working, ultimately these were the least offensive. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a few more comments, but it LGTM overall.
Good job 💪
const input = _input; | ||
export const unsafeEvaluate = (input: any, code: string, timeout: number) => { | ||
const vmContext = { | ||
input, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We stopped passing ethers
, I think that one is rather necessary.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I think we should also pass all our airnode-* packages.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I fear it will be confusing and harder to document and I do not see an use for using Airnode packages. If you this this is improtant we can keep it, but otherwise I'd just pass ethers
and axios
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's difficult to know what's useful for the future.
At minimum anything can be achieved given the built-in node modules (like I re-implemented the axios
requirement using built-in https
in the target code snippet). Everything outside of the built in modules is convenience.
I'll remove the airnode-*
require/imports :)
Done a few more updates, hopefully it is acceptable :P |
I will split up |
fe83877
to
451bcb6
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code LGTM 👍 (but I haven't tested manually).
I do not see any more issues just by looking at the code and I believe this was (is) tested by you on the issue you work on.
@@ -23,5 +23,6 @@ describe('constants', () => { | |||
expect(constants.PRIORITY_FEE).toEqual(3120000000); | |||
expect(constants.BASE_FEE_MULTIPLIER).toEqual(2); | |||
expect(constants.MAXIMUM_ONCHAIN_ERROR_LENGTH).toEqual(100); | |||
expect(constants.PROCESSING_TIMEOUT).toEqual(10_000); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ignore this. We set 30 seconds timeout and postprocessing can only take 10 seconds. So in worst case the API call has only 20 seconds to finish, but that is still all right.
I also think that we need a timer, because it is possible that there will be an infinite loop or something and we should not wait forever until the preprocessing finishes.
return; | ||
} | ||
|
||
// Delete oldest cache entries first |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I find it a strange design that we actually can exceed the CACHE_MAX_FILES
when adding a new key - but I don't have better suggestion atm.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We would have to sweep on every key addition which would slow things down. We have a lot of overhead @ 20k vs 130k files. It's not "correct" but it is highly unlikely, probably impossible on Lambda, for the cache file count to jump by 110k files in one cycle (Airnode would not be able to process that many requests on Lambda).
@@ -23,5 +23,6 @@ describe('constants', () => { | |||
expect(constants.PRIORITY_FEE).toEqual(3120000000); | |||
expect(constants.BASE_FEE_MULTIPLIER).toEqual(2); | |||
expect(constants.MAXIMUM_ONCHAIN_ERROR_LENGTH).toEqual(100); | |||
expect(constants.PROCESSING_TIMEOUT).toEqual(10_000); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Btw. your solution handles timeouts well, but I think it would be nice to add a test which tests that. Something like:
const preProcessingSpecifications = [
{
environment: 'Node 14' as const,
value: 'const output = {...input, from: `ETH`}; while(true);',
timeoutMs: 5_000,
},
...
@Siegrift : Regarding
and
I assume you mean I should ignore the first comment? I think the timeouts are robust and they definitely work in practice. |
Yeah. |
Thanks again for your input and patience @Siegrift :) |
This PR extends #1008
and adds asynchronous pre and post processing, which enables some fun use cases, like OAuth2. It also adds a caching utility set, but the caching utilities are not currently used in Airnode. The caching is currently being used by my OAuth2 snippet and I anticipate that it will eventually be used by per-endpoint configurable per
requestId
API response caching (a requirement for RNG).OAuth2 has many different flow variations and different providers have vastly different ideas on how to implement OAuth2. This PR allows us to implement arbitrary authentication logic prior to a request being generated (until such time as our formal OAuth2 config is standardised and stable). This allows us to support PoCs in future without having many custom Airnode instances in the wild, which reduces maintenance time keeping forks up to date 🙏 .
sync
code follows this format:async
code should follow this format:resolve
is passed through a context object to avm
runtime which the code interacts with.I've separately played around a bit with a WASM variant of this, but it isn't as powerful due to OS linkage issues. Snippets can be written in a separate project and processed using webpack to create static-like JS snippets which don't have to rely on Airnode's libraries, although the payloads are quite large (530KB for something that uses
ethers
andaxios
).