diff --git a/changelog.txt b/changelog.txt index 404ffb503..e69de29bb 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1 +0,0 @@ -feature - Allow specifying retry policies for event triggered functions. diff --git a/spec/function-builder.spec.ts b/spec/function-builder.spec.ts index 1ba12c7fa..b0c4d4c28 100644 --- a/spec/function-builder.spec.ts +++ b/spec/function-builder.spec.ts @@ -79,29 +79,14 @@ describe('FunctionBuilder', () => { it('should allow valid runtime options to be set', () => { const fn = functions .runWith({ - failurePolicy: { retry: {} }, - memory: '256MB', timeoutSeconds: 90, + memory: '256MB', }) .auth.user() .onCreate((user) => user); expect(fn.__trigger.availableMemoryMb).to.deep.equal(256); expect(fn.__trigger.timeout).to.deep.equal('90s'); - expect(fn.__trigger.failurePolicy).to.deep.equal({ retry: {} }); - }); - - it("should apply a default failure policy if it's aliased with `true`", () => { - const fn = functions - .runWith({ - failurePolicy: true, - memory: '256MB', - timeoutSeconds: 90, - }) - .auth.user() - .onCreate((user) => user); - - expect(fn.__trigger.failurePolicy).to.deep.equal({ retry: {} }); }); it('should allow both supported region and valid runtime options to be set', () => { @@ -147,26 +132,7 @@ describe('FunctionBuilder', () => { functions .region('asia-northeast1') .runWith({ timeoutSeconds: 600, memory: '256MB' }); - }).to.throw(Error, 'RuntimeOptions.timeoutSeconds'); - }); - - it('should throw an error if user chooses a failurePolicy which is neither an object nor a boolean', () => { - expect(() => - functions.runWith({ - failurePolicy: (1234 as unknown) as functions.RuntimeOptions['failurePolicy'], - }) - ).to.throw( - Error, - 'RuntimeOptions.failurePolicy must be a boolean or an object' - ); - }); - - it('should throw an error if user chooses a failurePolicy.retry which is not an object', () => { - expect(() => - functions.runWith({ - failurePolicy: { retry: (1234 as unknown) as object }, - }) - ).to.throw(Error, 'RuntimeOptions.failurePolicy.retry'); + }).to.throw(Error, 'TimeoutSeconds'); }); it('should throw an error if user chooses an invalid memory allocation', () => { @@ -188,13 +154,13 @@ describe('FunctionBuilder', () => { return functions.runWith({ timeoutSeconds: 1000000, } as any); - }).to.throw(Error, 'RuntimeOptions.timeoutSeconds'); + }).to.throw(Error, 'TimeoutSeconds'); expect(() => { return functions.region('asia-east2').runWith({ timeoutSeconds: 1000000, } as any); - }).to.throw(Error, 'RuntimeOptions.timeoutSeconds'); + }).to.throw(Error, 'TimeoutSeconds'); }); it('should throw an error if user chooses an invalid region', () => { diff --git a/src/cloud-functions.ts b/src/cloud-functions.ts index b18c965d7..1309aba61 100644 --- a/src/cloud-functions.ts +++ b/src/cloud-functions.ts @@ -22,13 +22,7 @@ import { Request, Response } from 'express'; import * as _ from 'lodash'; -import { - DEFAULT_FAILURE_POLICY, - DeploymentOptions, - FailurePolicy, - MEMORY_LOOKUP, - Schedule, -} from './function-configuration'; +import { DeploymentOptions, Schedule } from './function-configuration'; export { Request, Response }; /** @hidden */ @@ -208,7 +202,6 @@ export namespace Change { if (json.fieldMask) { before = applyFieldMask(before, json.after, json.fieldMask); } - return Change.fromObjects( customizer(before || {}), customizer(json.after || {}) @@ -223,8 +216,7 @@ export namespace Change { ) { const before = _.assign({}, after); const masks = fieldMask.split(','); - - masks.forEach((mask) => { + _.forEach(masks, (mask) => { const val = _.get(sparseBefore, mask); if (typeof val === 'undefined') { _.unset(before, mask); @@ -232,7 +224,6 @@ export namespace Change { _.set(before, mask, val); } }); - return before; } } @@ -262,7 +253,6 @@ export interface TriggerAnnotated { resource: string; service: string; }; - failurePolicy?: FailurePolicy; httpsTrigger?: {}; labels?: { [key: string]: string }; regions?: string[]; @@ -322,40 +312,6 @@ export interface MakeCloudFunctionArgs { triggerResource: () => string; } -/** @hidden */ -export function optionsToTrigger({ - failurePolicy: failurePolicyOrAlias, - memory, - regions, - schedule, - timeoutSeconds, -}: DeploymentOptions): TriggerAnnotated['__trigger'] { - /* - * FailurePolicy can be aliased with a boolean value in the public API. - * Convert aliases `true` and `false` to a standardized interface. - */ - const failurePolicy: FailurePolicy | undefined = - failurePolicyOrAlias === false - ? undefined - : failurePolicyOrAlias === true - ? DEFAULT_FAILURE_POLICY - : failurePolicyOrAlias; - - const availableMemoryMb: number | undefined = - memory === undefined ? undefined : MEMORY_LOOKUP[memory]; - - const timeout: string | undefined = - timeoutSeconds === undefined ? undefined : `${timeoutSeconds}s`; - - return { - ...(failurePolicy === undefined ? {} : { failurePolicy }), - ...(availableMemoryMb === undefined ? {} : { availableMemoryMb }), - ...(regions === undefined ? {} : { regions }), - ...(schedule === undefined ? {} : { schedule }), - ...(timeout === undefined ? {} : { timeout }), - }; -} - /** @hidden */ export function makeCloudFunction({ after = () => {}, @@ -507,3 +463,28 @@ function _detectAuthType(event: Event) { } return 'UNAUTHENTICATED'; } + +/** @hidden */ +export function optionsToTrigger(options: DeploymentOptions) { + const trigger: any = {}; + if (options.regions) { + trigger.regions = options.regions; + } + if (options.timeoutSeconds) { + trigger.timeout = options.timeoutSeconds.toString() + 's'; + } + if (options.memory) { + const memoryLookup = { + '128MB': 128, + '256MB': 256, + '512MB': 512, + '1GB': 1024, + '2GB': 2048, + }; + trigger.availableMemoryMb = _.get(memoryLookup, options.memory); + } + if (options.schedule) { + trigger.schedule = options.schedule; + } + return trigger; +} diff --git a/src/function-builder.ts b/src/function-builder.ts index 13fd30990..580e0498b 100644 --- a/src/function-builder.ts +++ b/src/function-builder.ts @@ -27,7 +27,6 @@ import { CloudFunction, EventContext } from './cloud-functions'; import { DeploymentOptions, MAX_TIMEOUT_SECONDS, - MIN_TIMEOUT_SECONDS, RuntimeOptions, SUPPORTED_REGIONS, VALID_MEMORY_OPTIONS, @@ -46,62 +45,28 @@ import * as testLab from './providers/testLab'; /** * Assert that the runtime options passed in are valid. * @param runtimeOptions object containing memory and timeout information. - * @throws { Error } FailurePolicy, Memory and TimeoutSeconds values must be - * valid. + * @throws { Error } Memory and TimeoutSeconds values must be valid. */ -function assertRuntimeOptionsValidity(runtimeOptions: RuntimeOptions): void { - if (_.isObjectLike(runtimeOptions) === false) { - throw new Error('RuntimeOptions must be an object.'); - } - - const { failurePolicy, memory, timeoutSeconds } = runtimeOptions; - - if (failurePolicy !== undefined) { - if ( - _.isBoolean(failurePolicy) === false && - _.isObjectLike(failurePolicy) === false - ) { - throw new Error( - `RuntimeOptions.failurePolicy must be a boolean or an object.` - ); - } - - if (typeof failurePolicy === 'object') { - if ( - _.isObjectLike(failurePolicy.retry) === false || - _.isEmpty(failurePolicy.retry) === false - ) { - throw new Error( - 'RuntimeOptions.failurePolicy.retry must be an empty object.' - ); - } - } - } - - if (memory !== undefined) { - if (_.includes(VALID_MEMORY_OPTIONS, memory) === false) { - throw new Error( - `RuntimeOptions.memory must be one of: ${VALID_MEMORY_OPTIONS.join( - ', ' - )}.` - ); - } +function assertRuntimeOptionsValid(runtimeOptions: RuntimeOptions): boolean { + if ( + runtimeOptions.memory && + !_.includes(VALID_MEMORY_OPTIONS, runtimeOptions.memory) + ) { + throw new Error( + `The only valid memory allocation values are: ${VALID_MEMORY_OPTIONS.join( + ', ' + )}` + ); } - - if (timeoutSeconds !== undefined) { - if (typeof timeoutSeconds !== 'number') { - throw new Error('RuntimeOptions.timeoutSeconds must be a number.'); - } - - if ( - timeoutSeconds < MIN_TIMEOUT_SECONDS || - timeoutSeconds > MAX_TIMEOUT_SECONDS - ) { - throw new Error( - `RuntimeOptions.timeoutSeconds must be between ${MIN_TIMEOUT_SECONDS} and ${MAX_TIMEOUT_SECONDS}.` - ); - } + if ( + runtimeOptions.timeoutSeconds > MAX_TIMEOUT_SECONDS || + runtimeOptions.timeoutSeconds < 0 + ) { + throw new Error( + `TimeoutSeconds must be between 0 and ${MAX_TIMEOUT_SECONDS}` + ); } + return true; } /** @@ -109,16 +74,16 @@ function assertRuntimeOptionsValidity(runtimeOptions: RuntimeOptions): void { * @param regions list of regions. * @throws { Error } Regions must be in list of supported regions. */ -function assertRegionsValidity(regions: string[]): void { - if (regions.length === 0) { - throw new Error('You must specify at least one region.'); +function assertRegionsAreValid(regions: string[]): boolean { + if (!regions.length) { + throw new Error('You must specify at least one region'); } - - if (_.difference(regions, SUPPORTED_REGIONS).length !== 0) { + if (_.difference(regions, SUPPORTED_REGIONS).length) { throw new Error( - `The only valid regions are: ${SUPPORTED_REGIONS.join(', ')}.` + `The only valid regions are: ${SUPPORTED_REGIONS.join(', ')}` ); } + return true; } /** @@ -132,27 +97,23 @@ function assertRegionsValidity(regions: string[]): void { export function region( ...regions: Array ): FunctionBuilder { - assertRegionsValidity(regions); - - return new FunctionBuilder({ regions }); + if (assertRegionsAreValid(regions)) { + return new FunctionBuilder({ regions }); + } } /** * Configure runtime options for the function. * @param runtimeOptions Object with three optional fields: - * 1. failurePolicy: failure policy of the function, with boolean `true` being - * equivalent to providing an empty retry object. - * 2. memory: amount of memory to allocate to the function, with possible - * values being '128MB', '256MB', '512MB', '1GB', and '2GB'. - * 3. timeoutSeconds: timeout for the function in seconds, with possible - * values being 0 to 540. - * - * Value must not be null. + * 1. memory: amount of memory to allocate to the function, possible values + * are: '128MB', '256MB', '512MB', '1GB', and '2GB'. + * 2. timeoutSeconds: timeout for the function in seconds, possible values are + * 0 to 540. */ export function runWith(runtimeOptions: RuntimeOptions): FunctionBuilder { - assertRuntimeOptionsValidity(runtimeOptions); - - return new FunctionBuilder(runtimeOptions); + if (assertRuntimeOptionsValid(runtimeOptions)) { + return new FunctionBuilder(runtimeOptions); + } } export class FunctionBuilder { @@ -167,40 +128,28 @@ export class FunctionBuilder { * functions.region('us-east1', 'us-central1') */ region(...regions: Array): FunctionBuilder { - assertRegionsValidity(regions); - - this.options.regions = regions; - - return this; + if (assertRegionsAreValid(regions)) { + this.options.regions = regions; + return this; + } } /** * Configure runtime options for the function. * @param runtimeOptions Object with three optional fields: - * 1. failurePolicy: failure policy of the function, with boolean `true` being - * equivalent to providing an empty retry object. - * 2. memory: amount of memory to allocate to the function, with possible - * values being '128MB', '256MB', '512MB', '1GB', and '2GB'. - * 3. timeoutSeconds: timeout for the function in seconds, with possible - * values being 0 to 540. - * - * Value must not be null. + * 1. memory: amount of memory to allocate to the function, possible values + * are: '128MB', '256MB', '512MB', '1GB', and '2GB'. + * 2. timeoutSeconds: timeout for the function in seconds, possible values are + * 0 to 540. */ runWith(runtimeOptions: RuntimeOptions): FunctionBuilder { - assertRuntimeOptionsValidity(runtimeOptions); - - this.options = _.assign(this.options, runtimeOptions); - - return this; + if (assertRuntimeOptionsValid(runtimeOptions)) { + this.options = _.assign(this.options, runtimeOptions); + return this; + } } get https() { - if (this.options.failurePolicy !== undefined) { - console.warn( - 'RuntimeOptions.failurePolicy is not supported in https functions.' - ); - } - return { /** * Handle HTTP requests. @@ -212,8 +161,7 @@ export class FunctionBuilder { ) => https._onRequestWithOptions(handler, this.options), /** * Declares a callable method for clients to call using a Firebase SDK. - * @param handler A method that takes a data and context and returns - * a value. + * @param handler A method that takes a data and context and returns a value. */ onCall: ( handler: ( diff --git a/src/function-configuration.ts b/src/function-configuration.ts index f3883155b..ec1695ccd 100644 --- a/src/function-configuration.ts +++ b/src/function-configuration.ts @@ -32,19 +32,6 @@ export const VALID_MEMORY_OPTIONS = [ '2GB', ] as const; -/** - * A mapping of memory options to its representation in the Cloud Functions API. - */ -export const MEMORY_LOOKUP: { - [Name in typeof VALID_MEMORY_OPTIONS[number]]: number; -} = { - '128MB': 128, - '256MB': 256, - '512MB': 512, - '1GB': 1024, - '2GB': 2048, -}; - /** * Scheduler retry options. Applies only to scheduled functions. */ @@ -65,20 +52,7 @@ export interface Schedule { retryConfig?: ScheduleRetryConfig; } -export interface FailurePolicy { - retry: {}; -} - -export const DEFAULT_FAILURE_POLICY: FailurePolicy = { - retry: {}, -}; - export interface RuntimeOptions { - /** - * Failure policy of the function, with boolean `true` being equivalent to - * providing an empty retry object. - */ - failurePolicy?: FailurePolicy | boolean; /** * Amount of memory to allocate to the function. */