diff --git a/.changeset/tall-cameras-reply.md b/.changeset/tall-cameras-reply.md index 6e02321c650..f44eabadba9 100644 --- a/.changeset/tall-cameras-reply.md +++ b/.changeset/tall-cameras-reply.md @@ -1,5 +1,4 @@ --- -"@smithy/middleware-stack": minor "@smithy/smithy-client": minor --- diff --git a/packages/middleware-stack/src/MiddlewareStack.ts b/packages/middleware-stack/src/MiddlewareStack.ts index bfc6f18584b..52caaac9ad1 100644 --- a/packages/middleware-stack/src/MiddlewareStack.ts +++ b/packages/middleware-stack/src/MiddlewareStack.ts @@ -32,14 +32,7 @@ const getMiddlewareNameWithAliases = (name: string | undefined, aliases: Array 0 ? ` (a.k.a. ${aliases.join(",")})` : ""}`; }; -export const constructStack = ( - stackOptions: { - /** - * Optional change listener, called with stack instance when middleware added/removed. - */ - onChange?: (middlewareStack: MiddlewareStack) => void; - } = {} -): MiddlewareStack => { +export const constructStack = (): MiddlewareStack => { let absoluteEntries: AbsoluteMiddlewareEntry[] = []; let relativeEntries: RelativeMiddlewareEntry[] = []; let identifyOnResolve = false; @@ -229,7 +222,6 @@ export const constructStack = ( } } absoluteEntries.push(entry); - stackOptions.onChange?.(stack); }, addRelativeTo: (middleware: MiddlewareType, options: HandlerOptions & RelativeLocation) => { @@ -266,7 +258,6 @@ export const constructStack = ( } } relativeEntries.push(entry); - stackOptions.onChange?.(stack); }, clone: () => cloneTo(constructStack()), @@ -276,14 +267,8 @@ export const constructStack = ( }, remove: (toRemove: MiddlewareType | string): boolean => { - let isRemoved: boolean; - if (typeof toRemove === "string") { - isRemoved = removeByName(toRemove); - } else { - isRemoved = removeByReference(toRemove); - } - stackOptions.onChange?.(stack); - return isRemoved; + if (typeof toRemove === "string") return removeByName(toRemove); + else return removeByReference(toRemove); }, removeByTag: (toRemove: string): boolean => { @@ -302,7 +287,6 @@ export const constructStack = ( }; absoluteEntries = absoluteEntries.filter(filterCb); relativeEntries = relativeEntries.filter(filterCb); - stackOptions?.onChange?.(stack); return isRemoved; }, diff --git a/packages/smithy-client/src/client.spec.ts b/packages/smithy-client/src/client.spec.ts index 6dcde8cdfe3..ff8325945fb 100644 --- a/packages/smithy-client/src/client.spec.ts +++ b/packages/smithy-client/src/client.spec.ts @@ -9,7 +9,7 @@ describe("SmithyClient", () => { const getCommandWithOutput = (output: string) => ({ resolveMiddleware: mockResolveMiddleware, }); - const client = new Client({} as any); + const client = new Client({ cacheMiddleware: true } as any); beforeEach(() => { jest.clearAllMocks(); @@ -67,11 +67,5 @@ describe("SmithyClient", () => { await expect(client.send(getCommandWithOutput("foo") as any, {})).resolves.toEqual("foo"); expect(privateAccess()).toBeUndefined(); }); - - it("should clear the handler cache when the middleareStack is modified", async () => { - await expect(client.send(getCommandWithOutput("foo") as any)).resolves.toEqual("foo"); - client.middlewareStack.add((n) => (a) => n(a)); - expect(privateAccess()).toBeUndefined(); - }); }); }); diff --git a/packages/smithy-client/src/client.ts b/packages/smithy-client/src/client.ts index 1afcb911ad2..2ed72dfb32e 100644 --- a/packages/smithy-client/src/client.ts +++ b/packages/smithy-client/src/client.ts @@ -25,6 +25,22 @@ export interface SmithyConfiguration { * @internal */ readonly apiVersion: string; + /** + * @public + * + * Default false. + * + * When true, the client will only resolve the middleware stack once per + * Command class. This means modifying the middlewareStack of the + * command or client after requests have been made will not be + * recognized. + * + * Calling client.destroy() also clears this cache. + * + * Enable this only if needing the additional time saved (0-1ms per request) + * and not needing middleware modifications between requests. + */ + cacheMiddleware?: boolean; } /** @@ -33,6 +49,7 @@ export interface SmithyConfiguration { export type SmithyResolvedConfiguration = { requestHandler: RequestHandler; readonly apiVersion: string; + cacheMiddleware?: boolean; }; /** @@ -45,20 +62,13 @@ export class Client< ResolvedClientConfiguration extends SmithyResolvedConfiguration, > implements IClient { - public middlewareStack: MiddlewareStack = constructStack({ - onChange: () => { - delete this.handlers; - }, - }); + public middlewareStack: MiddlewareStack = constructStack(); /** * May be used to cache the resolved handler function for a Command class. */ private handlers?: WeakMap> | undefined; - private configRef?: ResolvedClientConfiguration | undefined; - constructor(public readonly config: ResolvedClientConfiguration) { - this.configRef = this.config; - } + constructor(public readonly config: ResolvedClientConfiguration) {} send( command: Command>, @@ -81,7 +91,7 @@ export class Client< const options = typeof optionsOrCb !== "function" ? optionsOrCb : undefined; const callback = typeof optionsOrCb === "function" ? (optionsOrCb as (err: any, data?: OutputType) => void) : cb; - const useHandlerCache = options === undefined && this.config === this.configRef; + const useHandlerCache = options === undefined && this.config.cacheMiddleware === true; let handler: Handler; @@ -100,7 +110,6 @@ export class Client< } else { delete this.handlers; handler = command.resolveMiddleware(this.middlewareStack as any, this.config, options); - this.configRef = this.config; } if (callback) {