Skip to content

Commit

Permalink
fix(command-dev): invoke functions from runtime (#2826)
Browse files Browse the repository at this point in the history
  • Loading branch information
eduardoboucas authored Jul 11, 2021
1 parent 8bfdb2f commit 2c6a57a
Show file tree
Hide file tree
Showing 18 changed files with 600 additions and 570 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ jobs:
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
# NETLIFY_TEST_GITHUB_TOKEN is used to avoid reaching GitHub API limits in exec-fetcher.js
NETLIFY_TEST_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Changes the polling interval used by the file watcher
CHOKIDAR_INTERVAL: 20
- name: Get test coverage flags
id: test-coverage-flags
run: |-
Expand Down
29 changes: 9 additions & 20 deletions src/lib/functions/background.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
const lambdaLocal = require('lambda-local')

const { NETLIFYDEVERR, NETLIFYDEVLOG } = require('../../utils/logo')

const { DEFAULT_LAMBDA_OPTIONS, formatLambdaError, SECONDS_TO_MILLISECONDS, styleFunctionName } = require('./utils')
const { formatLambdaError, styleFunctionName } = require('./utils')

const BACKGROUND_FUNCTION_STATUS_CODE = 202

const createBackgroundFunctionCallback = (functionName) => (err) => {
const handleBackgroundFunction = (functionName, response) => {
console.log(`${NETLIFYDEVLOG} Queueing background function ${styleFunctionName(functionName)} for execution`)
response.status(BACKGROUND_FUNCTION_STATUS_CODE)
response.end()
}

const handleBackgroundFunctionResult = (functionName, err) => {
if (err) {
console.log(
`${NETLIFYDEVERR} Error during background function ${styleFunctionName(functionName)} execution:`,
Expand All @@ -17,19 +21,4 @@ const createBackgroundFunctionCallback = (functionName) => (err) => {
}
}

const executeBackgroundFunction = ({ event, lambdaPath, timeout, clientContext, response, functionName }) => {
console.log(`${NETLIFYDEVLOG} Queueing background function ${styleFunctionName(functionName)} for execution`)
response.status(BACKGROUND_FUNCTION_STATUS_CODE)
response.end()

return lambdaLocal.execute({
...DEFAULT_LAMBDA_OPTIONS,
event,
lambdaPath,
clientContext,
callback: createBackgroundFunctionCallback(functionName),
timeoutMs: timeout * SECONDS_TO_MILLISECONDS,
})
}

module.exports = { executeBackgroundFunction }
module.exports = { handleBackgroundFunction, handleBackgroundFunctionResult }
137 changes: 0 additions & 137 deletions src/lib/functions/builder.js

This file was deleted.

8 changes: 4 additions & 4 deletions src/lib/functions/form-submissions-handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const getRawBody = require('raw-body')
const { BACKGROUND } = require('../../utils/get-functions')
const { capitalize } = require('../string')

const createFormSubmissionHandler = function ({ getFunctionByName, siteUrl, warn }) {
const createFormSubmissionHandler = function ({ functionsRegistry, siteUrl, warn }) {
return async function formSubmissionHandler(req, res, next) {
if (req.url.startsWith('/.netlify/') || req.method !== 'POST') return next()

Expand All @@ -20,7 +20,7 @@ const createFormSubmissionHandler = function ({ getFunctionByName, siteUrl, warn
})
fakeRequest.headers = req.headers

const handlerName = getFormHandler({ getFunctionByName, warn })
const handlerName = getFormHandler({ functionsRegistry, warn })
if (!handlerName) {
return next()
}
Expand Down Expand Up @@ -125,9 +125,9 @@ const createFormSubmissionHandler = function ({ getFunctionByName, siteUrl, warn
}
}

const getFormHandler = function ({ getFunctionByName, warn }) {
const getFormHandler = function ({ functionsRegistry, warn }) {
const handlers = ['submission-created', `submission-created${BACKGROUND}`]
.map((name) => getFunctionByName(name))
.map((name) => functionsRegistry.get(name))
.filter(Boolean)
.map(({ name }) => name)

Expand Down
4 changes: 1 addition & 3 deletions src/lib/functions/memoized-build.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
const DEBOUNCE_INTERVAL = 300

const cache = {}

// `memoizedBuild` will avoid running the same build command multiple times
// until the previous operation has been completed. If another call is made
// within that period, it will be:
Expand All @@ -10,7 +8,7 @@ const cache = {}
// This allows us to discard any duplicate filesystem events, while ensuring
// that actual updates happening during the zip operation will be executed
// after it finishes (only the last update will run).
const memoizedBuild = ({ cacheKey, command }) => {
const memoizedBuild = ({ cache, cacheKey, command }) => {
if (cache[cacheKey] === undefined) {
cache[cacheKey] = {
// eslint-disable-next-line promise/prefer-await-to-then
Expand Down
98 changes: 98 additions & 0 deletions src/lib/functions/netlify-function.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
const { difference } = require('../../utils/difference')

const BACKGROUND_SUFFIX = '-background'

class NetlifyFunction {
constructor({
config,
errorExit,
functionsDirectory,
mainFile,
name,
projectRoot,
runtime,
timeoutBackground,
timeoutSynchronous,
}) {
this.config = config
this.errorExit = errorExit
this.functionsDirectory = functionsDirectory
this.mainFile = mainFile
this.name = name
this.projectRoot = projectRoot
this.runtime = runtime
this.timeoutBackground = timeoutBackground
this.timeoutSynchronous = timeoutSynchronous

// Determines whether this is a background function based on the function
// name.
this.isBackground = name.endsWith(BACKGROUND_SUFFIX)

// List of the function's source files. This starts out as an empty set
// and will get populated on every build.
this.srcFiles = new Set()
}

// The `build` method transforms source files into invocable functions. Its
// return value is an object with:
//
// - `srcFilesDiff`: Files that were added and removed since the last time
// the function was built.
async build({ cache }) {
const buildFunction = await this.runtime.getBuildFunction({
config: this.config,
errorExit: this.errorExit,
func: this,
functionsDirectory: this.functionsDirectory,
projectRoot: this.projectRoot,
})

this.buildQueue = buildFunction({ cache })

try {
const { srcFiles, ...buildData } = await this.buildQueue
const srcFilesSet = new Set(srcFiles)
const srcFilesDiff = this.getSrcFilesDiff(srcFilesSet)

this.buildData = buildData
this.srcFiles = srcFilesSet

return { srcFilesDiff }
} catch (error) {
return { error }
}
}

// Compares a new set of source files against a previous one, returning an
// object with two Sets, one with added and the other with deleted files.
getSrcFilesDiff(newSrcFiles) {
const added = difference(newSrcFiles, this.srcFiles)
const deleted = difference(this.srcFiles, newSrcFiles)

return {
added,
deleted,
}
}

// Invokes the function and returns its response object.
async invoke(event, context) {
await this.buildQueue

const timeout = this.isBackground ? this.timeoutBackground : this.timeoutSynchronous

try {
const result = await this.runtime.invokeFunction({
context,
event,
func: this,
timeout,
})
return { result, error: null }
} catch (error) {
return { result: null, error }
}
}
}

module.exports = { NetlifyFunction }
Loading

1 comment on commit 2c6a57a

@github-actions
Copy link

Choose a reason for hiding this comment

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

📊 Benchmark results

Package size: 330 MB

Please sign in to comment.