faastjs
Version:
Serverless batch computing made simple.
654 lines • 112 kB
JavaScript
"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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