From c3aa2c4c2cff28317e00ff23460758b47c7c47f5 Mon Sep 17 00:00:00 2001 From: Daniel Castro Date: Tue, 31 Oct 2023 16:04:50 -0700 Subject: [PATCH] Add native support for warmup trigger (#180) * Add warmup trigger * Additional changes to types * Add back trigger property * Minor changes to docs, types, signatures * Revert a few minor edits * PR review suggestions * Add interface for warmupContext --- src/addBindingName.ts | 4 ++-- src/app.ts | 5 +++++ src/trigger.ts | 9 +++++++++ types/app.d.ts | 13 +++++++++++++ types/index.d.ts | 1 + types/trigger.d.ts | 6 ++++++ types/warmup.d.ts | 17 +++++++++++++++++ 7 files changed, 53 insertions(+), 2 deletions(-) create mode 100644 types/warmup.d.ts diff --git a/src/addBindingName.ts b/src/addBindingName.ts index 6073e97..9373d59 100644 --- a/src/addBindingName.ts +++ b/src/addBindingName.ts @@ -1,13 +1,13 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT License. +export { InvocationContext } from './InvocationContext'; export { HttpRequest } from './http/HttpRequest'; export { HttpResponse } from './http/HttpResponse'; -export { InvocationContext } from './InvocationContext'; const bindingCounts: Record = {}; /** - * If the host spawns multiple workers, it expects the metadata (including binding name) to be the same accross workers + * If the host spawns multiple workers, it expects the metadata (including binding name) to be the same across workers. * That means we need to generate binding names in a deterministic fashion, so we'll do that using a count * There's a tiny risk users register bindings in a non-deterministic order (i.e. async race conditions), but it's okay considering the following: * 1. We will track the count individually for each binding type. This makes the names more readable and reduces the chances a race condition will matter diff --git a/src/app.ts b/src/app.ts index 8dc80a8..7c90e80 100644 --- a/src/app.ts +++ b/src/app.ts @@ -19,6 +19,7 @@ import { StorageBlobFunctionOptions, StorageQueueFunctionOptions, TimerFunctionOptions, + WarmupFunctionOptions, } from '@azure/functions'; import * as coreTypes from '@azure/functions-core'; import { CoreInvocationContext, FunctionCallback } from '@azure/functions-core'; @@ -145,6 +146,10 @@ export function cosmosDB(name: string, options: CosmosDBFunctionOptions): void { generic(name, convertToGenericOptions(options, trigger.cosmosDB)); } +export function warmup(name: string, options: WarmupFunctionOptions): void { + generic(name, convertToGenericOptions(options, trigger.warmup)); +} + export function generic(name: string, options: GenericFunctionOptions): void { if (!hasSetup) { setup(); diff --git a/src/trigger.ts b/src/trigger.ts index bdda8ee..d7749fd 100644 --- a/src/trigger.ts +++ b/src/trigger.ts @@ -22,6 +22,8 @@ import { StorageQueueTriggerOptions, TimerTrigger, TimerTriggerOptions, + WarmupTrigger, + WarmupTriggerOptions, } from '@azure/functions'; import { addBindingName } from './addBindingName'; @@ -90,6 +92,13 @@ export function cosmosDB(options: CosmosDBTriggerOptions): CosmosDBTrigger { }); } +export function warmup(options: WarmupTriggerOptions): WarmupTrigger { + return addTriggerBindingName({ + ...options, + type: 'warmupTrigger', + }); +} + export function generic(options: GenericTriggerOptions): FunctionTrigger { return addTriggerBindingName(options); } diff --git a/types/app.d.ts b/types/app.d.ts index 64a6d9c..dffcda9 100644 --- a/types/app.d.ts +++ b/types/app.d.ts @@ -9,6 +9,7 @@ import { HttpFunctionOptions, HttpHandler, HttpMethodFunctionOptions } from './h import { ServiceBusQueueFunctionOptions, ServiceBusTopicFunctionOptions } from './serviceBus'; import { StorageBlobFunctionOptions, StorageQueueFunctionOptions } from './storage'; import { TimerFunctionOptions } from './timer'; +import { WarmupFunctionOptions } from './warmup'; /** * Registers an http function in your app that will be triggered by making a request to the function url @@ -143,6 +144,18 @@ export function eventGrid(name: string, options: EventGridFunctionOptions): void */ export function cosmosDB(name: string, options: CosmosDBFunctionOptions): void; +/** + * Registers a function in your app that will be triggered when an instance is added to scale a running function app. + * The warmup trigger is only called during scale-out operations, not during restarts or other non-scale startups. + * Make sure your logic can load all required dependencies without relying on the warmup trigger. + * Lazy loading is a good pattern to achieve this goal. + * The warmup trigger isn't available to apps running on the Consumption plan. + * For more information, please see the [Azure Functions warmup trigger documentation](https://learn.microsoft.com/azure/azure-functions/functions-bindings-warmup?tabs=isolated-process&pivots=programming-language-javascript). + * @param name The name of the function. The name must be unique within your app and will mostly be used for your own tracking purposes + * @param options Configuration options describing the inputs, outputs, and handler for this function + */ +export function warmup(name: string, options: WarmupFunctionOptions): void; + /** * Registers a generic function in your app that will be triggered based on the type specified in `options.trigger.type` * Use this method if your desired trigger type does not already have its own method diff --git a/types/index.d.ts b/types/index.d.ts index 5880bbe..5cb8843 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -20,6 +20,7 @@ export * from './storage'; export * from './table'; export * from './timer'; export * as trigger from './trigger'; +export * from './warmup'; /** * Void if no `return` output is registered diff --git a/types/trigger.d.ts b/types/trigger.d.ts index f58af4f..bfae17c 100644 --- a/types/trigger.d.ts +++ b/types/trigger.d.ts @@ -20,6 +20,7 @@ import { StorageQueueTriggerOptions, } from './storage'; import { TimerTrigger, TimerTriggerOptions } from './timer'; +import { WarmupTrigger, WarmupTriggerOptions } from './warmup'; /** * [Link to docs and examples](https://docs.microsoft.com/azure/azure-functions/functions-bindings-http-webhook-trigger?&pivots=programming-language-javascript) @@ -66,6 +67,11 @@ export function eventGrid(options: EventGridTriggerOptions): EventGridTrigger; */ export function cosmosDB(options: CosmosDBTriggerOptions): CosmosDBTrigger; +/** + * [Link to docs and examples](https://learn.microsoft.com/azure/azure-functions/functions-bindings-warmup?tabs=isolated-process&pivots=programming-language-javascript) + */ +export function warmup(options: WarmupTriggerOptions): WarmupTrigger; + /** * A generic option that can be used for any trigger type * Use this method if your desired trigger type does not already have its own method diff --git a/types/warmup.d.ts b/types/warmup.d.ts new file mode 100644 index 0000000..cea229c --- /dev/null +++ b/types/warmup.d.ts @@ -0,0 +1,17 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. + +import { FunctionOptions, FunctionResult, FunctionTrigger } from './index'; +import { InvocationContext } from './InvocationContext'; + +export interface WarmupContextOptions {} +export type WarmupHandler = (warmupContext: WarmupContextOptions, context: InvocationContext) => FunctionResult; + +export interface WarmupFunctionOptions extends WarmupTriggerOptions, Partial { + handler: WarmupHandler; + + trigger?: WarmupTrigger; +} + +export interface WarmupTriggerOptions {} +export type WarmupTrigger = FunctionTrigger & WarmupTriggerOptions;