UNPKG

faastjs

Version:

Serverless batch computing made simple.

654 lines 112 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.faastLocal = exports.faastAws = exports.faast = exports.FaastModuleProxy = exports.FunctionStatsEvent = exports.providers = void 0; const tslib_1 = require("tslib"); const events_1 = require("events"); const module_1 = tslib_1.__importDefault(require("module")); const url_1 = require("url"); const util_1 = require("util"); const uuid_1 = require("uuid"); const aws_faast_1 = require("./aws/aws-faast"); const cost_1 = require("./cost"); const error_1 = require("./error"); const local_faast_1 = require("./local/local-faast"); const log_1 = require("./log"); const metrics_1 = require("./metrics"); const provider_1 = require("./provider"); const serialize_1 = require("./serialize"); const shared_1 = require("./shared"); const throttle_1 = require("./throttle"); const wrapper_1 = require("./wrapper"); /** * An array of all available provider. * @public */ exports.providers = ["aws", "local"]; async function createFaastModuleProxy(impl, fmodule, userOptions) { try { const resolvedModule = resolve(fmodule); const functionId = (0, uuid_1.v4)(); const options = { ...impl.defaults, ...userOptions }; log_1.log.provider(`options ${(0, log_1.inspectProvider)(options)}`); return new FaastModuleProxy(impl, await impl.initialize(resolvedModule, functionId, options), fmodule, resolvedModule, options); } catch (err) { throw new error_1.FaastError(err, "could not initialize cloud function"); } } /** * Summarize statistics about cloud function invocations. * @public */ class FunctionStatsEvent { /** * @internal */ constructor( /** The name of the cloud function the statistics are about. */ fn, /** See {@link FunctionStats}. */ stats) { this.fn = fn; this.stats = stats; this.stats = stats.clone(); } /** * Returns a string summarizing the statistics event. * @remarks * The string includes number of completed calls, errors, and retries, and * the mean execution time for the calls that completed within the last time * interval (1s). */ toString() { const executionTime = this.stats ? this.stats.executionTime.mean : 0; return `[${this.fn}] ${this.stats}, executionTime: ${(executionTime / 1000).toFixed(2)}s`; } } exports.FunctionStatsEvent = FunctionStatsEvent; class PendingRequest { constructor(call) { this.call = call; this.queue = new throttle_1.AsyncOrderedQueue(); this.created = Date.now(); } } /** * Implementation of {@link FaastModule}. * @remarks * `FaastModuleProxy` provides a unified developer experience for faast.js * modules on top of provider-specific runtime APIs. Most users will not create * `FaastModuleProxy` instances themselves; instead use {@link faast}, or * {@link faastAws} or {@link faastLocal}. * `FaastModuleProxy` implements the {@link FaastModule} interface, which is the * preferred public interface for faast modules. `FaastModuleProxy` can be used * to access provider-specific details and state, and is useful for deeper * testing. * @public */ class FaastModuleProxy { /** * Constructor * @internal */ constructor(impl, /** @internal */ state, fmodule, modulePath, /** The options set for this instance, which includes default values. */ options) { this.impl = impl; this.state = state; this.fmodule = fmodule; this.modulePath = modulePath; this.options = options; /** The {@link Provider}, e.g. "aws". */ this.provider = this.impl.name; /** @internal */ this._stats = new metrics_1.FunctionStatsMap(); this._cpuUsage = new metrics_1.FactoryMap(() => new metrics_1.FactoryMap((_) => new metrics_1.FunctionCpuUsage())); this._skew = new shared_1.ExponentiallyDecayingAverageValue(0.3); this._cleanupHooks = new Set(); this._initialInvocationTime = new metrics_1.FactoryMap(() => Date.now()); this._callResultsPending = new Map(); this._emitter = new events_1.EventEmitter(); log_1.log.info(`Node version: ${process.version}`); log_1.log.provider(`name: ${this.impl.name}`); log_1.log.provider(`responseQueueId: ${this.impl.responseQueueId(state)}`); log_1.log.provider(`logUrl: ${this.impl.logUrl(state)}`); log_1.log.info(`Log url: ${impl.logUrl(state)}`); this._funnel = new throttle_1.Funnel(options.concurrency); if (options.rate) { this._rateLimiter = new throttle_1.RateLimiter(options.rate, 1); } this._memoryLeakDetector = new metrics_1.MemoryLeakDetector(options.memorySize); const functionsDetail = {}; const functions = {}; for (const name of Object.keys(fmodule)) { const origFunction = fmodule[name]; if (typeof origFunction === "function") { if ((0, wrapper_1.isGenerator)(origFunction)) { const func = this.wrapGenerator(origFunction); functionsDetail[name] = func; functions[name] = async function* (...args) { const generator = func(...args); for await (const iter of generator) { yield iter.value; } }; } else { const func = this.wrapFunction(origFunction); functionsDetail[name] = func; functions[name] = (...args) => func(...args).then(p => p.value); } } } this.functions = functions; this.functionsDetail = functionsDetail; this._collectorPump = new throttle_1.Pump({ concurrency: 2 }, () => this.resultCollector()); this._collectorPump.start(); } /** {@inheritdoc FaastModule.cleanup} */ async cleanup(userCleanupOptions = {}) { try { this._stats.clear(); this._memoryLeakDetector.clear(); this._funnel.clear(); this._rateLimiter?.clear(); this._cleanupHooks.forEach(hook => hook.resolve()); this._cleanupHooks.clear(); this._emitter.removeAllListeners(); this.stopStats(); this._initialInvocationTime.clear(); this._callResultsPending.clear(); this._collectorPump.stop(); log_1.log.provider(`cleanup`); const options = { ...provider_1.CleanupOptionDefaults, ...userCleanupOptions }; const { gcTimeout } = options; let timedout = false; if (gcTimeout > 0) { const timeout = (0, shared_1.sleep)(gcTimeout * 1000).then(() => (timedout = true)); await Promise.race([this.impl.cleanup(this.state, options), timeout]); } else { await this.impl.cleanup(this.state, options); } if (timedout) { log_1.log.provider(`cleanup timed out after ${gcTimeout}s`); } else { log_1.log.provider(`cleanup done`); } } catch (err) { throw new error_1.FaastError(err, "failed in cleanup"); } } /** {@inheritdoc FaastModule.logUrl} */ logUrl() { const rv = this.impl.logUrl(this.state); log_1.log.provider(`logUrl ${rv}`); return rv; } startStats(interval = 1000) { this._statsTimer = setInterval(() => { this._stats.fIncremental.forEach((stats, fn) => { this._emitter.emit("stats", new FunctionStatsEvent(fn, stats)); }); this._stats.resetIncremental(); }, interval); } stopStats() { this._statsTimer && clearInterval(this._statsTimer); this._statsTimer = undefined; } /** {@inheritdoc FaastModule.on} */ on(name, listener) { if (!this._statsTimer) { this.startStats(); } this._emitter.on(name, listener); } /** {@inheritdoc FaastModule.off} */ off(name, listener) { this._emitter.off(name, listener); if (this._emitter.listenerCount(name) === 0) { this.stopStats(); } } async withCancellation(fn) { const deferred = new throttle_1.Deferred(); this._cleanupHooks.add(deferred); const promise = fn(deferred.promise); try { return await promise; } finally { this._cleanupHooks.delete(deferred); } } processResponse(returned, functionName, localStartTime) { const { response } = returned; const { logUrl, instanceId, memoryUsage } = response; let value; if (response.type === "reject") { const error = response.isErrorObject ? (0, error_1.synthesizeFaastError)({ errObj: returned.value, logUrl: ` ${logUrl} `, functionName }) : returned.value; value = Promise.reject(error); value.catch((_silenceWarningLackOfSynchronousCatch) => { }); } else { const { executionId } = returned.response; const detail = { value: returned.value[0], logUrl, executionId, instanceId, memoryUsage }; value = Promise.resolve(detail); } const { localRequestSentTime, remoteResponseSentTime, localEndTime } = returned; const { remoteExecutionStartTime, remoteExecutionEndTime } = response; const fstats = this._stats; if (remoteExecutionStartTime && remoteExecutionEndTime) { const localStartLatency = localRequestSentTime - localStartTime; const roundTripLatency = localEndTime - localRequestSentTime; const executionTime = remoteExecutionEndTime - remoteExecutionStartTime; const sendResponseLatency = Math.max(0, (remoteResponseSentTime || remoteExecutionEndTime) - remoteExecutionEndTime); const networkLatency = roundTripLatency - executionTime - sendResponseLatency; const estimatedRemoteStartTime = localRequestSentTime + networkLatency / 2; const estimatedSkew = estimatedRemoteStartTime - remoteExecutionStartTime; let skew = estimatedSkew; if (fstats.aggregate.completed > 1) { this._skew.update(skew); skew = this._skew.value; } const remoteStartLatency = Math.max(1, remoteExecutionStartTime + skew - localRequestSentTime); const returnLatency = Math.max(1, localEndTime - (remoteExecutionEndTime + skew)); fstats.update(functionName, "localStartLatency", localStartLatency); fstats.update(functionName, "remoteStartLatency", remoteStartLatency); fstats.update(functionName, "executionTime", executionTime); fstats.update(functionName, "sendResponseLatency", sendResponseLatency); fstats.update(functionName, "returnLatency", returnLatency); const billed = (executionTime || 0) + (sendResponseLatency || 0); const estimatedBilledTime = Math.max(100, Math.ceil(billed / 100) * 100); fstats.update(functionName, "estimatedBilledTime", estimatedBilledTime); } if (response.type === "reject") { fstats.incr(functionName, "errors"); } else { fstats.incr(functionName, "completed"); } if (instanceId && memoryUsage) { if (this._memoryLeakDetector.detectedNewLeak(functionName, instanceId, memoryUsage)) { log_1.log.leaks(`Possible memory leak detected in function '${functionName}'.`); log_1.log.leaks(`Memory use before execution leaked from prior calls: %O`, memoryUsage); log_1.log.leaks(`Logs: ${logUrl} `); log_1.log.leaks(`These logs show only one example faast cloud function invocation that may have a leak.`); } } return value; } invoke(fname, args, callId) { const ResponseQueueId = this.impl.responseQueueId(this.state); const callObject = { name: fname, args: (0, serialize_1.serializeFunctionArgs)(fname, args, this.options.validateSerialization), callId, modulePath: this.modulePath, ResponseQueueId }; log_1.log.calls(`Calling '${fname}' (${callId})`); const pending = new PendingRequest(callObject); this._callResultsPending.set(callId, pending); if (this._collectorPump.stopped) { this._collectorPump.start(); } this.withCancellation(async (cancel) => { await this.impl.invoke(this.state, pending.call, cancel).catch(err => pending.queue.pushImmediate({ response: { kind: "promise", type: "reject", callId, isErrorObject: typeof err === "object" && err instanceof Error, value: (0, serialize_1.serialize)(err) }, value: err, localEndTime: Date.now(), localRequestSentTime: pending.created })); }); return pending; } lookupFname(fn) { let fname = fn.name; if (!fname) { for (const key of Object.keys(this.fmodule)) { if (this.fmodule[key] === fn) { fname = key; log_1.log.info(`Found arrow function name: ${key}`); break; } } } if (!fname) { throw new error_1.FaastError(`Could not find function name`); } return fname; } createCallId() { return (0, uuid_1.v4)(); } wrapGenerator(fn) { return (...args) => { const startTime = Date.now(); let fname = this.lookupFname(fn); const callId = this.createCallId(); const pending = this.invoke(fname, args, callId); log_1.log.provider(`invoke ${(0, log_1.inspectProvider)(pending.call)}`); this._stats.incr(fname, "invocations"); return { [Symbol.asyncIterator]() { return this; }, next: () => pending.queue.next().then(async (next) => { const promise = this.processResponse(next, fname, startTime); const result = await promise; log_1.log.calls(`yielded ${(0, util_1.inspect)(result)}`); const { value, ...rest } = result; if (result.value.done) { this.clearPending(callId); return { done: true, value: rest }; } else { return { done: false, value: { ...rest, value: value.value } }; } }) }; }; } clearPending(callId) { this._callResultsPending.delete(callId); if (this._callResultsPending.size === 0) { this._collectorPump.stop(); } } wrapFunction(fn) { return (...args) => { const startTime = Date.now(); let fname = this.lookupFname(fn); const callId = this.createCallId(); const tryInvoke = async () => { const pending = this.invoke(fname, args, callId); log_1.log.provider(`invoke ${(0, log_1.inspectProvider)(pending.call)}`); this._stats.incr(fname, "invocations"); const responsePromise = pending.queue.next(); const rv = await responsePromise; this.clearPending(callId); log_1.log.calls(`Returning '${fname}' (${callId}): ${(0, util_1.inspect)(rv)}`); return this.processResponse(rv, fname, startTime); }; const funnel = this._funnel; let retries = 0; const shouldRetry = (err) => { if (err instanceof error_1.FaastError) { if (error_1.FaastError.hasCauseWithName(err, error_1.FaastErrorNames.ESERIALIZE)) { return false; } // Don't retry user-generated errors. Only errors caused by // failures of operations faast itself initiated (e.g. cloud // service APIs) are retried. if (error_1.FaastError.hasCauseWithName(err, error_1.FaastErrorNames.EEXCEPTION)) { return false; } } if (retries < this.options.maxRetries) { retries++; this._stats.incr(fname, "retries"); log_1.log.info(`faast: func: ${fname} attempts: ${retries}, err: ${(0, log_1.inspectProvider)(err)}`); return true; } return false; }; if (this._rateLimiter) { return funnel.push(() => this._rateLimiter.push(tryInvoke), shouldRetry); } else { return funnel.push(tryInvoke, shouldRetry); } }; } /** {@inheritdoc FaastModule.costSnapshot} */ async costSnapshot() { const estimate = await this.impl.costSnapshot(this.state, this._stats.aggregate); log_1.log.provider(`costSnapshot returned ${(0, log_1.inspectProvider)(estimate)}`); if (this._stats.aggregate.retries > 0) { const { retries, invocations } = this._stats.aggregate; const retryPct = ((retries / invocations) * 100).toFixed(1); estimate.push(new cost_1.CostMetric({ name: "retries", pricing: 0, measured: retries, unit: "retry", unitPlural: "retries", comment: `Retries were ${retryPct}% of requests and may have incurred charges not accounted for by faast.`, informationalOnly: true })); } return estimate; } /** {@inheritdoc FaastModule.stats} */ stats(functionName) { if (functionName) { return this._stats.fAggregate.getOrCreate(functionName).clone(); } return this._stats.aggregate.clone(); } async resultCollector() { const { _callResultsPending: callResultsPending } = this; if (!callResultsPending.size) { return; } log_1.log.provider(`polling ${this.impl.responseQueueId(this.state)}`); const pollResult = await this.withCancellation(cancel => this.impl.poll(this.state, cancel)); log_1.log.provider(`poll returned ${(0, log_1.inspectProvider)(pollResult)}`); const { Messages, isFullMessageBatch } = pollResult; const localEndTime = Date.now(); this.adjustCollectorConcurrencyLevel(isFullMessageBatch); for (const m of Messages) { switch (m.kind) { case "functionstarted": { const pending = callResultsPending.get(m.callId); if (pending) { pending.executing = true; } break; } case "promise": case "iterator": try { const { timestamp } = m; const value = (0, serialize_1.deserialize)(m.value); const pending = callResultsPending.get(m.callId); if (pending) { const rv = { response: m, value, remoteResponseSentTime: timestamp, localRequestSentTime: pending.created, localEndTime }; log_1.log.provider(`returned ${(0, log_1.inspectProvider)(value)}`); if (m.kind === "iterator") { pending.queue.push(rv, m.sequence); } else { pending.queue.pushImmediate(rv); } } else { log_1.log.info(`Pending promise not found for CallId: ${m.callId}`); } } catch (err) { log_1.log.warn(err); } break; case "cpumetrics": const { metrics } = m; const pending = callResultsPending.get(m.callId); if (!pending) { return; } const stats = this._cpuUsage.getOrCreate(pending.call.name); const secondMetrics = stats.getOrCreate(Math.round(metrics.elapsed / 1000)); secondMetrics.stime.update(metrics.stime); secondMetrics.utime.update(metrics.utime); secondMetrics.cpuTime.update(metrics.stime + metrics.utime); break; } } } adjustCollectorConcurrencyLevel(full) { const nPending = this._callResultsPending.size; if (nPending > 0) { let nCollectors = full ? Math.floor(nPending / 20) + 2 : 2; nCollectors = Math.min(nCollectors, 10); const pump = this._collectorPump; const previous = pump.concurrency; pump.setMaxConcurrency(nCollectors); if (previous !== pump.concurrency) { log_1.log.info(`Result collectors running: ${pump.getConcurrency()}, new max: ${pump.concurrency}`); } } } } exports.FaastModuleProxy = FaastModuleProxy; function resolve(fmodule) { if ("FAAST_URL" in fmodule) { const url = fmodule["FAAST_URL"]; if (typeof url !== "string") { throw new error_1.FaastError({ info: { module: fmodule } }, `FAAST_URL must be a string.`); } return (0, url_1.fileURLToPath)(url); } const cache = module_1.default._cache; let modulePath; for (const key of Object.keys(cache).reverse()) { if (cache[key].exports === fmodule) { modulePath = key; break; } } if (!modulePath) { throw new error_1.FaastError({ info: { module: fmodule } }, `Could not find file for module, must use "import * as X from Y" or "X = require(Y)" to load a module for faast. For ESM modules, export const FAAST_URL = import.meta.url from the functions module.`); } log_1.log.info(`Found file: ${modulePath}`); return modulePath; } /** * The main entry point for faast with any provider and only common options. * @param provider - One of `"aws"` or `"local"`. See * {@link Provider}. * @param fmodule - A module imported with `import * as X from "Y";`. Using * `require` also works but loses type information. * @param options - See {@link CommonOptions}. * @returns See {@link FaastModule}. * @remarks * Example of usage: * ```typescript * import { faast } from "faastjs"; * import * as mod from "./path/to/module"; * (async () => { * const faastModule = await faast("aws", mod); * try { * const result = await faastModule.functions.func("arg"); * } finally { * await faastModule.cleanup(); * } * })(); * ``` * @public */ async function faast(provider, fmodule, options) { switch (provider) { case "aws": return faastAws(fmodule, options); case "local": return faastLocal(fmodule, options); default: throw new error_1.FaastError(`Unknown cloud provider option '${provider}'`); } } exports.faast = faast; /** * The main entry point for faast with AWS provider. * @param fmodule - A module imported with `import * as X from "Y";`. Using * `require` also works but loses type information. * @param options - Most common options are in {@link CommonOptions}. * Additional AWS-specific options are in {@link AwsOptions}. * @public */ function faastAws(fmodule, options) { return createFaastModuleProxy(aws_faast_1.AwsImpl, fmodule, options); } exports.faastAws = faastAws; /** * The main entry point for faast with Local provider. * @param fmodule - A module imported with `import * as X from "Y";`. Using * `require` also works but loses type information. * @param options - Most common options are in {@link CommonOptions}. * Additional Local-specific options are in {@link LocalOptions}. * @returns a Promise for {@link LocalFaastModule}. * @public */ function faastLocal(fmodule, options) { return createFaastModuleProxy(local_faast_1.LocalImpl, fmodule, options); } exports.faastLocal = faastLocal; function estimateFunctionLatency(fnStats) { const { executionTime, localStartLatency, remoteStartLatency, returnLatency } = fnStats; return (localStartLatency.mean + remoteStartLatency.mean + executionTime.mean + returnLatency.mean || 0); } function estimateTailLatency(fnStats, nStdDev) { return estimateFunctionLatency(fnStats) + nStdDev * fnStats.executionTime.stdev; } async function retryFunctionIfNeededToReduceTailLatency(timeSinceInitialInvocation, getTimeout, worker, shouldRetry, cancel) { let pending = true; let lastInvocationTime = Date.now(); cancel.then(() => (pending = false)); const doWork = async () => { lastInvocationTime = Date.now(); await worker().catch(_ => { }); pending = false; }; const latency = () => Date.now() - lastInvocationTime; doWork(); while (pending) { const timeout = getTimeout(); if (latency() >= timeout && timeSinceInitialInvocation() > timeout + 1000) { if (shouldRetry()) { doWork(); } else { return; } } const waitTime = (0, shared_1.roundTo100ms)(Math.max(timeout - latency(), 5000)); await (0, shared_1.sleep)(waitTime, cancel); } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmFhc3QuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvZmFhc3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7OztBQUFBLG1DQUFzQztBQUN0Qyw0REFBNEI7QUFDNUIsNkJBQW9DO0FBQ3BDLCtCQUErQjtBQUMvQiwrQkFBb0M7QUFDcEMsK0NBQWdFO0FBQ2hFLGlDQUFrRDtBQUNsRCxtQ0FBNEU7QUFDNUUscURBQTBFO0FBQzFFLCtCQUE2QztBQUM3Qyx1Q0FLbUI7QUFDbkIseUNBV29CO0FBQ3BCLDJDQUE0RTtBQUM1RSxxQ0FBa0Y7QUFDbEYseUNBQW9GO0FBQ3BGLHVDQUFzRDtBQUV0RDs7O0dBR0c7QUFDVSxRQUFBLFNBQVMsR0FBZSxDQUFDLEtBQUssRUFBRSxPQUFPLENBQUMsQ0FBQztBQXdHdEQsS0FBSyxVQUFVLHNCQUFzQixDQUNqQyxJQUF3QixFQUN4QixPQUFVLEVBQ1YsV0FBZTtJQUVmLElBQUksQ0FBQztRQUNELE1BQU0sY0FBYyxHQUFHLE9BQU8sQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUN4QyxNQUFNLFVBQVUsR0FBRyxJQUFBLFNBQU0sR0FBVSxDQUFDO1FBQ3BDLE1BQU0sT0FBTyxHQUFnQixFQUFFLEdBQUcsSUFBSSxDQUFDLFFBQVEsRUFBRSxHQUFHLFdBQVcsRUFBRSxDQUFDO1FBQ2xFLFNBQUcsQ0FBQyxRQUFRLENBQUMsV0FBVyxJQUFBLHFCQUFlLEVBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBQ3BELE9BQU8sSUFBSSxnQkFBZ0IsQ0FDdkIsSUFBSSxFQUNKLE1BQU0sSUFBSSxDQUFDLFVBQVUsQ0FBQyxjQUFjLEVBQUUsVUFBVSxFQUFFLE9BQU8sQ0FBQyxFQUMxRCxPQUFPLEVBQ1AsY0FBYyxFQUNkLE9BQWtDLENBQ3JDLENBQUM7SUFDTixDQUFDO0lBQUMsT0FBTyxHQUFRLEVBQUUsQ0FBQztRQUNoQixNQUFNLElBQUksa0JBQVUsQ0FBQyxHQUFHLEVBQUUscUNBQXFDLENBQUMs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