faastjs
Version:
Serverless batch computing made simple.
654 lines • 111 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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmFhc3QuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvZmFhc3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7OztBQUFBLG1DQUFzQztBQUN0Qyw0REFBNEI7QUFDNUIsNkJBQW9DO0FBQ3BDLCtCQUErQjtBQUMvQiwrQkFBb0M7QUFDcEMsK0NBQWdFO0FBQ2hFLGlDQUFrRDtBQUNsRCxtQ0FBNEU7QUFDNUUscURBQTBFO0FBQzFFLCtCQUE2QztBQUM3Qyx1Q0FLbUI7QUFDbkIseUNBV29CO0FBQ3BCLDJDQUE0RTtBQUM1RSxxQ0FBa0Y7QUFDbEYseUNBQW9GO0FBQ3BGLHVDQUFzRDtBQUV0RDs7O0dBR0c7QUFDVSxRQUFBLFNBQVMsR0FBZSxDQUFDLEtBQUssRUFBRSxPQUFPLENBQUMsQ0FBQztBQXdHdEQsS0FBSyxVQUFVLHNCQUFzQixDQUNqQyxJQUF3QixFQUN4QixPQUFVLEVBQ1YsV0FBZTtJQUVmLElBQUk7UUFDQSxNQUFNLGNBQWMsR0FBRyxPQUFPLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDeEMsTUFBTSxVQUFVLEdBQUcsSUFBQSxTQUFNLEdBQVUsQ0FBQztRQUNwQyxNQUFNLE9BQU8sR0FBZ0IsRUFBRSxHQUFHLElBQUksQ0FBQyxRQUFRLEVBQUUsR0FBRyxXQUFXLEVBQUUsQ0FBQztRQUNsRSxTQUFHLENBQUMsUUFBUSxDQUFDLFdBQVcsSUFBQSxxQkFBZSxFQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUNwRCxPQUFPLElBQUksZ0JBQWdCLENBQ3ZCLElBQUksRUFDSixNQUFNLElBQUksQ0FBQyxVQUFVLENBQUMsY0FBYyxFQUFFLFVBQVUsRUFBRSxPQUFPLENBQUMsRUFDMUQsT0FBTyxFQUNQLGNBQWMsRUFDZCxPQUFrQyxDQUNyQyxDQUFDO0tBQ0w7SUFBQyxPQUFPLEdBQVEsRUFBRTtRQUNmLE1BQU0sSUFBSSxrQkFBVSxDQUFDLEdBQUcsRUFBRSxxQ0FBcUMsQ0FBQyxDQUFDO0tBQ3BFO0FBQ0ws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