Skip to content
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

Use Deno cache to hydrate the deno dependencies, so they're pre-cached #136

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

hicksy
Copy link

@hicksy hicksy commented May 27, 2021

Hi 👋

This PR would work alongside this one in Sandbox - architect/sandbox#585

Together they enable hydration for deno runtime arc functions by setting the DENO_DIR to vendor/.deno_cache within each lambda and using deno cache to pre-cache the remote dependencies

This massively speeds up individual invocation and stops issues where the lambda times out while Deno is caching the remote dependencies.

Also could prove to be a handy pre-cache that could be used by the Deno lambda layer, moving the .deno_cache to /tmp to deploy pre-cached / hydrated Deno functions

I've not worked up any tests yet, to feedback you could test with this basic repo - https://github.com/hicksy/deno-arc-example-login-flow - before the change the lambda will prob time out, with these PRs it'll hydrate during sandbox start and invoke promptly.

Thank you for helping out! ✨

We really appreciate your commitment to improving Architect

To maintain a high standard of quality in our releases, before merging every pull request we ask that you've completed the following:

  • Forked the repo and created your branch from master
  • Made sure tests pass (run npm it from the repo root)
  • Expanded test coverage related to your changes:
    • Added and/or updated unit tests (if appropriate)
    • Added and/or updated integration tests (if appropriate)
  • Updated relevant documentation:
  • Summarized your changes in changelog.md
  • Linked to any related issues, PRs, etc. below that may relate to, consume, or necessitate these changes

Please also be sure to completed the CLA (if you haven't already).

Learn more about contributing to Architect here.

Thanks again!

@@ -34,6 +34,7 @@ module.exports = function hydrator (params, callback) {
let isJs = file.endsWith('package.json')
let isPy = file.endsWith('requirements.txt')
let isRb = file.endsWith('Gemfile')
let isDeno = file.endsWith('deps.ts') || file.endsWith('index.js') || file.endsWith('index.ts') || file.endsWith('index.tsx') || file.endsWith('mod.js') || file.endsWith('mod.ts') || file.endsWith('mod.tsx')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like we can tidy this up with an array + a some() check

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, cool. No probs. Will push some amends later

@@ -43,7 +44,9 @@ module.exports = function hydrator (params, callback) {
if (isJs) dir = join(cwd, 'node_modules')
if (isPy) dir = join(cwd, 'vendor')
if (isRb) dir = join(cwd, 'vendor', 'bundle')
rm(dir, callback)
if (isDeno) callback()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why would we skip Deno? We definitely need a fresh function when hydrating, we don't know when the last time dependencies were pulled or what state they're in, this prevents a lot of transient dependency issues (and enables Sandbox symlinking).

Copy link
Author

@hicksy hicksy May 28, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe I've misunderstood - I thought the rm of those dirs was because for the other runtimes the shared & view folders are symlinked into the dependency folder? So like in node you can
let sharedFunc = require('@architect/shared/function.js)

I was thinking because in Deno vendor is just a standard dir it wouldn't need cleaning up?

@@ -103,6 +106,12 @@ module.exports = function hydrator (params, callback) {
exec(`bundle update`, options, callback)
}

// cache deno deps.ts
else if (isDeno) {
// should --reload be added? That would force re-caching everytime, so maybe not?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hydrate is responsible for deterministic deploys, prob not a bad idea to use --reload but I'm not sure what the re-caching operations are in Deno-land – can you speak to that at all?

Copy link
Author

@hicksy hicksy May 28, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A little, so my understanding of Deno's cache is that any remote URL that's imported is cached, and the cache is stored as a reference to the URL. A file with a filename hash (of the pathname I think) stored in $DENO_DIR/deps/<http|s>/<hostname>

So (I think) it works like this:

  1. is the import a remote URL. If so, it'll be downloaded and cached (unless it's already cached, in which case its imported from the cache location)

If the --reload flag is supplied to either deno cache or deno run then regardless of whether the file is in the cache already, the remote URL will be downloaded and cached prior to import

  1. If it's a local import, that doesn't get cached.

I guess the downside of always using --reload will be the wasteful nature of downloading the same files over and over (slightly unavoidable on the first sandbox start as we're using discreet DENO_DIR local to the lambda).

But the downside to deno cache is it works great when your URL is pinned to a specific version, but if it's a generic like https://esm.sh/react-helmet then that URL will be cached even though over time that may be serving v2, v3, etc

So maybe it is best to take the hit, at least pre-caching like this keeps the invocations nice and fast

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, damn, bummer about the import-URLs-with-no-version. With that in mind I guess it makes sense to --reload all the time. As was said, we take the performance hit up-front at author time during hydrate (and thus before a deploy or sandbox run) in order to keep runtime performant.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, sure. Latest commit takes that approach

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You'll see Deno's cache output in stdout, can add --quiet to the cache command to prevent that

Also, as we're caching the lambda handler, this doesn't quite follow the format of the logging

✓ Hydrate Successfully hydrated dependencies
⚬ Hydrate Hydrating dependencies in 1 path
✓ Hydrate Hydrated frontend/home//home/

Hydrate Hydrated frontend/home//home/ should really be Hydrate Hydrated frontend/home/index.tsx

Think that uses dirname somewhere?

src/index.js Outdated
@@ -69,6 +70,30 @@ function hydrator (inventory, installing, params, callback) {
if (viewsDir && file.includes(viewsDir)) return false
return true
})

// Add deno cacheable files if they exist and we're hyrdrating a Deno runtime
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure this change would be the right approach. How about adding these to the glob pattern, and then filter for Deno by entry files on Deno Lambdas?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, cool. No probs. Will push some amends later

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does the latest commit work better?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

3 participants