UNPKG

22.9 kBTypeScriptView Raw
1import { FaastModule } from "../index";
2import { AwsOptions } from "./aws/aws-faast";
3import { GoogleOptions } from "./google/google-faast";
4import { FunctionStats, CommonOptions } from "./provider";
5import { PropertiesExcept, AnyFunction } from "./types";
6/**
7 * A line item in the cost estimate, including the resource usage metric
8 * measured and its pricing.
9 * @public
10 */
11export declare class CostMetric {
12 /** The name of the cost metric, e.g. `functionCallDuration` */
13 readonly name: string;
14 /** The price in USD per unit measured. */
15 readonly pricing: number;
16 /** The name of the units that pricing is measured in for this metric. */
17 readonly unit: string;
18 /** The measured value of the cost metric, in units. */
19 readonly measured: number;
20 /**
21 * The plural form of the unit name. By default the plural form will be the
22 * name of the unit with "s" appended at the end, unless the last letter is
23 * capitalized, in which case there is no plural form (e.g. "GB").
24 */
25 readonly unitPlural?: string;
26 /**
27 * An optional comment, usually providing a link to the provider's pricing
28 * page and other data.
29 */
30 readonly comment?: string;
31 /**
32 * True if this cost metric is only for informational purposes (e.g. AWS's
33 * `logIngestion`) and does not contribute cost.
34 */
35 readonly informationalOnly?: boolean;
36 /** @internal */
37 constructor(arg: PropertiesExcept<CostMetric, AnyFunction>);
38 /**
39 * The cost contribution of this cost metric. Equal to
40 * {@link CostMetric.pricing} * {@link CostMetric.measured}.
41 */
42 cost(): number;
43 /**
44 * Return a string with the cost estimate for this metric, omitting
45 * comments.
46 */
47 describeCostOnly(): string;
48 /** Describe this cost metric, including comments. */
49 toString(): string;
50}
51/**
52 * A summary of the costs incurred by a faast.js module at a point in time.
53 * Output of {@link FaastModule.costSnapshot}.
54 * @remarks
55 * Cost information provided by faast.js is an estimate. It is derived from
56 * internal faast.js measurements and not by consulting data provided by your
57 * cloud provider.
58 *
59 * **Faast.js does not guarantee the accuracy of cost estimates.**
60 *
61 * **Use at your own risk.**
62 *
63 * Example using AWS:
64 * ```typescript
65 * const faastModule = await faast("aws", m);
66 * try {
67 * // Invoke faastModule.functions.*
68 * } finally {
69 * await faastModule.cleanup();
70 * console.log(`Cost estimate:`);
71 * console.log(`${await faastModule.costSnapshot()}`);
72 * }
73 * ```
74 *
75 * AWS example output:
76 * ```text
77 * Cost estimate:
78 * functionCallDuration $0.00002813/second 0.6 second $0.00001688 68.4% [1]
79 * sqs $0.00000040/request 9 requests $0.00000360 14.6% [2]
80 * sns $0.00000050/request 5 requests $0.00000250 10.1% [3]
81 * functionCallRequests $0.00000020/request 5 requests $0.00000100 4.1% [4]
82 * outboundDataTransfer $0.09000000/GB 0.00000769 GB $0.00000069 2.8% [5]
83 * logIngestion $0.50000000/GB 0 GB $0 0.0% [6]
84 * ---------------------------------------------------------------------------------------
85 * $0.00002467 (USD)
86 *
87 * * Estimated using highest pricing tier for each service. Limitations apply.
88 * ** Does not account for free tier.
89 * [1]: https://aws.amazon.com/lambda/pricing (rate = 0.00001667/(GB*second) * 1.6875 GB = 0.00002813/second)
90 * [2]: https://aws.amazon.com/sqs/pricing
91 * [3]: https://aws.amazon.com/sns/pricing
92 * [4]: https://aws.amazon.com/lambda/pricing
93 * [5]: https://aws.amazon.com/ec2/pricing/on-demand/#Data_Transfer
94 * [6]: https://aws.amazon.com/cloudwatch/pricing/ - Log ingestion costs not currently included.
95 * ```
96 *
97 * A cost snapshot contains several {@link CostMetric} values. Each `CostMetric`
98 * summarizes one component of the overall cost of executing the functions so
99 * far. Some cost metrics are common to all faast providers, and other metrics
100 * are provider-specific. The common metrics are:
101 *
102 * - `functionCallDuration`: the estimated billed CPU time (rounded to the next
103 * 100ms) consumed by completed cloud function calls. This is the metric that
104 * usually dominates cost.
105 *
106 * - `functionCallRequests`: the number of invocation requests made. Most
107 * providers charge for each invocation.
108 *
109 * Provider-specific metrics vary. For example, AWS has the following additional
110 * metrics:
111 *
112 * - `sqs`: AWS Simple Queueing Service. This metric captures the number of
113 * queue requests made to insert and retrieve queued results (each 64kb chunk
114 * is counted as an additional request). SQS is used even if
115 * {@link CommonOptions.mode} is not set to `"queue"`, because it is necessary
116 * for monitoring cloud function invocations.
117 *
118 * - `sns`: AWS Simple Notification Service. SNS is used to invoke Lambda
119 * functions when {@link CommonOptions.mode} is `"queue"`.
120 *
121 * - `outboundDataTransfer`: an estimate of the network data transferred out
122 * from the cloud provider for this faast.js module. This estimate only counts
123 * data returned from cloud function invocations and infrastructure that
124 * faast.js sets up. It does not count any outbound data sent by your cloud
125 * functions that are not known to faast.js. Note that if you run faast.js on
126 * EC2 in the same region (see {@link AwsOptions.region}), then the data
127 * transfer costs will be zero (however, the cost snapshot will not include
128 * EC2 costs). Also note that if your cloud function transfers data from/to S3
129 * buckets in the same region, there is no cost as long as that data is not
130 * returned from the function.
131 *
132 * - `logIngestion`: this cost metric is always zero for AWS. It is present to
133 * remind the user that AWS charges for log data ingested by CloudWatch Logs
134 * that are not measured by faast.js. Log entries may arrive significantly
135 * after function execution completes, and there is no way for faast.js to
136 * know exactly how long to wait, therefore it does not attempt to measure
137 * this cost. In practice, if your cloud functions do not perform extensive
138 * logging on all invocations, log ingestion costs from faast.js are likely to
139 * be low or fall within the free tier.
140 *
141 * For Google, extra metrics include `outboundDataTransfer` similar to AWS, and
142 * `pubsub`, which combines costs that are split into `sns` and `sqs` on AWS.
143 *
144 * The Local provider has no extra metrics.
145 *
146 * Prices are retrieved dynamically from AWS and Google and cached locally.
147 * Cached prices expire after 24h. For each cost metric, faast.js uses the
148 * highest price tier to compute estimated pricing.
149 *
150 * Cost estimates do not take free tiers into account.
151 * @public
152 */
153export declare class CostSnapshot {
154 /** The {@link Provider}, e.g. "aws" or "google" */
155 readonly provider: string;
156 /**
157 * The options used to initialize the faast.js module where this cost
158 * snapshot was generated.
159 */
160 readonly options: CommonOptions | AwsOptions | GoogleOptions;
161 /** The function statistics that were used to compute prices. */
162 readonly stats: FunctionStats;
163 /**
164 * The cost metric components for this cost snapshot. See
165 * {@link CostMetric}.
166 */
167 readonly costMetrics: CostMetric[];
168 /** @internal */
169 constructor(
170 /** The {@link Provider}, e.g. "aws" or "google" */
171 provider: string,
172 /**
173 * The options used to initialize the faast.js module where this cost
174 * snapshot was generated.
175 */
176 options: CommonOptions | AwsOptions | GoogleOptions, stats: FunctionStats, costMetrics?: CostMetric[]);
177 /** Sum of cost metrics. */
178 total(): number;
179 /** A summary of all cost metrics and prices in this cost snapshot. */
180 toString(): string;
181 /**
182 * Comma separated value output for a cost snapshot.
183 * @remarks
184 * The format is "metric,unit,pricing,measured,cost,percentage,comment".
185 *
186 * Example output:
187 * ```text
188 * metric,unit,pricing,measured,cost,percentage,comment
189 * functionCallDuration,second,0.00002813,0.60000000,0.00001688,64.1% ,"https://aws.amazon.com/lambda/pricing (rate = 0.00001667/(GB*second) * 1.6875 GB = 0.00002813/second)"
190 * functionCallRequests,request,0.00000020,5,0.00000100,3.8% ,"https://aws.amazon.com/lambda/pricing"
191 * outboundDataTransfer,GB,0.09000000,0.00000844,0.00000076,2.9% ,"https://aws.amazon.com/ec2/pricing/on-demand/#Data_Transfer"
192 * sqs,request,0.00000040,13,0.00000520,19.7% ,"https://aws.amazon.com/sqs/pricing"
193 * sns,request,0.00000050,5,0.00000250,9.5% ,"https://aws.amazon.com/sns/pricing"
194 * logIngestion,GB,0.50000000,0,0,0.0% ,"https://aws.amazon.com/cloudwatch/pricing/ - Log ingestion costs not currently included."
195 * ```
196 */
197 csv(): string;
198 /** @internal */
199 push(metric: CostMetric): void;
200 /**
201 * Find a specific cost metric by name.
202 * @returns a {@link CostMetric} if found, otherwise `undefined`.
203 */
204 find(name: string): CostMetric | undefined;
205}
206/**
207 * Analyze the cost of a workload across many provider configurations.
208 * @public
209 */
210export declare namespace CostAnalyzer {
211 /**
212 * An input to {@link CostAnalyzer.analyze}, specifying one
213 * configuration of faast.js to run against a workload. See
214 * {@link AwsOptions} and {@link GoogleOptions}.
215 * @public
216 */
217 type Configuration = {
218 provider: "aws";
219 options: AwsOptions;
220 } | {
221 provider: "google";
222 options: GoogleOptions;
223 };
224 /**
225 * Default AWS cost analyzer configurations include all memory sizes for AWS
226 * Lambda.
227 * @remarks
228 * The default AWS cost analyzer configurations include every memory size
229 * from 128MB to 3008MB in 64MB increments. Each configuration has the
230 * following settings:
231 *
232 * ```typescript
233 * {
234 * provider: "aws",
235 * options: {
236 * mode: "https",
237 * memorySize,
238 * timeout: 300,
239 * gc: "off",
240 * childProcess: true
241 * }
242 * }
243 * ```
244 *
245 * Use `Array.map` to change or `Array.filter` to remove some of these
246 * configurations. For example:
247 *
248 * ```typescript
249 * const configsWithAtLeast1GB = awsConfigurations.filter(c => c.memorySize > 1024)
250 * const shorterTimeout = awsConfigurations.map(c => ({...c, timeout: 60 }));
251 * ```
252 * @public
253 */
254 const awsConfigurations: Configuration[];
255 /**
256 * Default Google Cloud Functions cost analyzer configurations include all
257 * available memory sizes.
258 * @remarks
259 * Each google cost analyzer configuration follows this template:
260 *
261 * ```typescript
262 * {
263 * provider: "google",
264 * options: {
265 * mode: "https",
266 * memorySize,
267 * timeout: 300,
268 * gc: "off",
269 * childProcess: true
270 * }
271 * }
272 * ```
273 *
274 * where `memorySize` is in `[128, 256, 512, 1024, 2048]`.
275 * @public
276 */
277 const googleConfigurations: Configuration[];
278 /**
279 * User-defined custom metrics for a workload. These are automatically
280 * summarized in the output; see {@link CostAnalyzer.Workload}.
281 * @public
282 */
283 type WorkloadAttribute<A extends string> = {
284 [attr in A]: number;
285 };
286 /**
287 * A user-defined cost analyzer workload for {@link CostAnalyzer.analyze}.
288 * @public
289 * Example:
290 */
291 interface Workload<T extends object, A extends string> {
292 /**
293 * The imported module that contains the cloud functions to test.
294 */
295 funcs: T;
296 /**
297 * A function that executes cloud functions on
298 * `faastModule.functions.*`. The work function should return `void` if
299 * there are no custom workload attributes. Otherwise, it should return
300 * a {@link CostAnalyzer.WorkloadAttribute} object which maps
301 * user-defined attribute names to numerical values for the workload.
302 * For example, this might measure bandwidth or some other metric not
303 * tracked by faast.js, but are relevant for evaluating the
304 * cost-performance tradeoff of the configurations analyzed by the cost
305 * analyzer.
306 */
307 work: (faastModule: FaastModule<T>) => Promise<WorkloadAttribute<A> | void>;
308 /**
309 * An array of configurations to run the work function against (see
310 * {@link CostAnalyzer.Configuration}). For example, each entry in the
311 * array may specify a provider, memory size, and other options.
312 * Default: {@link CostAnalyzer.awsConfigurations}.
313 */
314 configurations?: Configuration[];
315 /**
316 * Combine {@link CostAnalyzer.WorkloadAttribute} instances returned
317 * from multiple workload executions (caused by value of
318 * {@link CostAnalyzer.Workload.repetitions}). The default is a function
319 * that takes the average of each attribute.
320 */
321 summarize?: (summaries: WorkloadAttribute<A>[]) => WorkloadAttribute<A>;
322 /**
323 * Format an attribute value for console output. This is displayed by
324 * the cost analyzer when all of the repetitions for a configuration
325 * have completed. The default returns
326 * `${attribute}:${value.toFixed(1)}`.
327 */
328 format?: (attr: A, value: number) => string;
329 /**
330 * Format an attribute value for CSV. The default returns
331 * `value.toFixed(1)`.
332 */
333 formatCSV?: (attr: A, value: number) => string;
334 /**
335 * If true, do not output live results to the console. Can be useful for
336 * running the cost analyzer as part of automated tests. Default: false.
337 */
338 silent?: boolean;
339 /**
340 * The number of repetitions to run the workload for each cost analyzer
341 * configuration. Higher repetitions help reduce the jitter in the
342 * results. Repetitions execute in the same FaastModule instance.
343 * Default: 10.
344 */
345 repetitions?: number;
346 /**
347 * The amount of concurrency to allow. Concurrency can arise from
348 * multiple repetitions of the same configuration, or concurrenct
349 * executions of different configurations. This concurrency limit
350 * throttles the total number of concurrent workload executions across
351 * both of these sources of concurrency. Default: 64.
352 */
353 concurrency?: number;
354 }
355 /**
356 * A cost estimate result for a specific cost analyzer configuration.
357 * @public
358 */
359 interface Estimate<A extends string> {
360 /**
361 * The cost snapshot for the cost analysis of the specific (workload,
362 * configuration) combination. See {@link CostSnapshot}.
363 */
364 costSnapshot: CostSnapshot;
365 /**
366 * The worload configuration that was analyzed. See
367 * {@link CostAnalyzer.Configuration}.
368 */
369 config: Configuration;
370 /**
371 * Additional workload metrics returned from the work function. See
372 * {@link CostAnalyzer.WorkloadAttribute}.
373 */
374 extraMetrics: WorkloadAttribute<A>;
375 }
376 /**
377 * Estimate the cost of a workload using multiple configurations and
378 * providers.
379 * @param userWorkload - a {@link CostAnalyzer.Workload} object specifying
380 * the workload to run and additional parameters.
381 * @returns A promise for a {@link CostAnalyzer.Result}
382 * @public
383 * @remarks
384 * It can be deceptively difficult to set optimal parameters for AWS Lambda
385 * and similar services. On the surface there appears to be only one
386 * parameter: memory size. Choosing more memory also gives more CPU
387 * performance, but it's unclear how much. It's also unclear where single
388 * core performance stops getting better. The workload cost analyzer solves
389 * these problems by making it easy to run cost experiments.
390 * ```text
391 * (AWS)
392 * ┌───────┐
393 * ┌────▶│ 128MB │
394 * │ └───────┘
395 * │ ┌───────┐
396 * ┌─────────────────┐ ├────▶│ 256MB │
397 * ┌──────────────┐ │ │ │ └───────┘
398 * │ workload │───▶│ │ │ ...
399 * └──────────────┘ │ │ │ ┌───────┐
400 * │ cost analyzer │─────┼────▶│3008MB │
401 * ┌──────────────┐ │ │ │ └───────┘
402 * │configurations│───▶│ │ │
403 * └──────────────┘ │ │ │ (Google)
404 * └─────────────────┘ │ ┌───────┐
405 * ├────▶│ 128MB │
406 * │ └───────┘
407 * │ ┌───────┐
408 * └────▶│ 256MB │
409 * └───────┘
410 * ```
411 * `costAnalyzer` is the entry point. It automatically runs this workload
412 * against multiple configurations in parallel. Then it uses faast.js' cost
413 * snapshot mechanism to automatically determine the price of running the
414 * workload with each configuration.
415 *
416 * Example:
417 *
418 * ```typescript
419 * // functions.ts
420 * export function randomNumbers(n: number) {
421 * let sum = 0;
422 * for (let i = 0; i < n; i++) {
423 * sum += Math.random();
424 * }
425 * return sum;
426 * }
427 *
428 * // cost-analyzer-example.ts
429 * import { writeFileSync } from "fs";
430 * import { CostAnalyzer, FaastModule } from "faastjs";
431 * import * as funcs from "./functions";
432 *
433 * async function work(faastModule: FaastModule<typeof funcs>) {
434 * await faastModule.functions.randomNumbers(100000000);
435 * }
436 *
437 * async function main() {
438 * const results = await CostAnalyzer.analyze({ funcs, work });
439 * writeFileSync("cost.csv", results.csv());
440 * }
441 *
442 * main();
443 * ```
444 *
445 * Example output (this is printed to `console.log` unless the
446 * {@link CostAnalyzer.Workload.silent} is `true`):
447 * ```text
448 * ✔ aws 128MB queue 15.385s 0.274σ $0.00003921
449 * ✔ aws 192MB queue 10.024s 0.230σ $0.00003576
450 * ✔ aws 256MB queue 8.077s 0.204σ $0.00003779
451 * ▲ ▲ ▲ ▲ ▲ ▲
452 * │ │ │ │ │ │
453 * provider │ mode │ stdev average
454 * │ │ execution estimated
455 * memory │ time cost
456 * size │
457 * average cloud
458 * execution time
459 * ```
460 *
461 * The output lists the provider, memory size, ({@link CommonOptions.mode}),
462 * average time of a single execution of the workload, the standard
463 * deviation (in seconds) of the execution time, and average estimated cost
464 * for a single run of the workload.
465 *
466 * The "execution time" referenced here is not wall clock time, but rather
467 * execution time in the cloud function. The execution time does not include
468 * any time the workload spends waiting locally. If the workload invokes
469 * multiple cloud functions, their execution times will be summed even if
470 * they happen concurrently. This ensures the execution time and cost are
471 * aligned.
472 */
473 function analyze<T extends object, A extends string>(userWorkload: Workload<T, A>): Promise<Result<T, A>>;
474 /**
475 * Cost analyzer results for each workload and configuration.
476 * @remarks
477 * The `estimates` property has the cost estimates for each configuration.
478 * See {@link CostAnalyzer.Estimate}.
479 * @public
480 */
481 class Result<T extends object, A extends string> {
482 /** The workload analyzed. */
483 readonly workload: Required<Workload<T, A>>;
484 /**
485 * Cost estimates for each configuration of the workload. See
486 * {@link CostAnalyzer.Estimate}.
487 */
488 readonly estimates: Estimate<A>[];
489 /** @internal */
490 constructor(
491 /** The workload analyzed. */
492 workload: Required<Workload<T, A>>,
493 /**
494 * Cost estimates for each configuration of the workload. See
495 * {@link CostAnalyzer.Estimate}.
496 */
497 estimates: Estimate<A>[]);
498 /**
499 * Comma-separated output of cost analyzer. One line per cost analyzer
500 * configuration.
501 * @remarks
502 * The columns are:
503 *
504 * - `memory`: The memory size allocated.
505 *
506 * - `cloud`: The cloud provider.
507 *
508 * - `mode`: See {@link CommonOptions.mode}.
509 *
510 * - `options`: A string summarizing other faast.js options applied to the
511 * `workload`. See {@link CommonOptions}.
512 *
513 * - `completed`: Number of repetitions that successfully completed.
514 *
515 * - `errors`: Number of invocations that failed.
516 *
517 * - `retries`: Number of retries that were attempted.
518 *
519 * - `cost`: The average cost of executing the workload once.
520 *
521 * - `executionTime`: the aggregate time spent executing on the provider for
522 * all cloud function invocations in the workload. This is averaged across
523 * repetitions.
524 *
525 * - `executionTimeStdev`: The standard deviation of `executionTime`.
526 *
527 * - `billedTime`: the same as `exectionTime`, except rounded up to the next
528 * 100ms for each invocation. Usually very close to `executionTime`.
529 */
530 csv(): string;
531 }
532}