Skip to content

Commit

Permalink
make handler cache configurable
Browse files Browse the repository at this point in the history
  • Loading branch information
kuhe committed Sep 6, 2024
1 parent 2da43c4 commit 78c26dd
Show file tree
Hide file tree
Showing 4 changed files with 24 additions and 38 deletions.
1 change: 0 additions & 1 deletion .changeset/tall-cameras-reply.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
---
"@smithy/middleware-stack": minor
"@smithy/smithy-client": minor
---

Expand Down
22 changes: 3 additions & 19 deletions packages/middleware-stack/src/MiddlewareStack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,7 @@ const getMiddlewareNameWithAliases = (name: string | undefined, aliases: Array<s
return `${name || "anonymous"}${aliases && aliases.length > 0 ? ` (a.k.a. ${aliases.join(",")})` : ""}`;
};

export const constructStack = <Input extends object, Output extends object>(
stackOptions: {
/**
* Optional change listener, called with stack instance when middleware added/removed.
*/
onChange?: (middlewareStack: MiddlewareStack<any, any>) => void;
} = {}
): MiddlewareStack<Input, Output> => {
export const constructStack = <Input extends object, Output extends object>(): MiddlewareStack<Input, Output> => {
let absoluteEntries: AbsoluteMiddlewareEntry<Input, Output>[] = [];
let relativeEntries: RelativeMiddlewareEntry<Input, Output>[] = [];
let identifyOnResolve = false;
Expand Down Expand Up @@ -229,7 +222,6 @@ export const constructStack = <Input extends object, Output extends object>(
}
}
absoluteEntries.push(entry);
stackOptions.onChange?.(stack);
},

addRelativeTo: (middleware: MiddlewareType<Input, Output>, options: HandlerOptions & RelativeLocation) => {
Expand Down Expand Up @@ -266,7 +258,6 @@ export const constructStack = <Input extends object, Output extends object>(
}
}
relativeEntries.push(entry);
stackOptions.onChange?.(stack);
},

clone: () => cloneTo(constructStack<Input, Output>()),
Expand All @@ -276,14 +267,8 @@ export const constructStack = <Input extends object, Output extends object>(
},

remove: (toRemove: MiddlewareType<Input, Output> | 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 => {
Expand All @@ -302,7 +287,6 @@ export const constructStack = <Input extends object, Output extends object>(
};
absoluteEntries = absoluteEntries.filter(filterCb);
relativeEntries = relativeEntries.filter(filterCb);
stackOptions?.onChange?.(stack);
return isRemoved;
},

Expand Down
8 changes: 1 addition & 7 deletions packages/smithy-client/src/client.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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();
});
});
});
31 changes: 20 additions & 11 deletions packages/smithy-client/src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,22 @@ export interface SmithyConfiguration<HandlerOptions> {
* @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;
}

/**
Expand All @@ -33,6 +49,7 @@ export interface SmithyConfiguration<HandlerOptions> {
export type SmithyResolvedConfiguration<HandlerOptions> = {
requestHandler: RequestHandler<any, any, HandlerOptions>;
readonly apiVersion: string;
cacheMiddleware?: boolean;
};

/**
Expand All @@ -45,20 +62,13 @@ export class Client<
ResolvedClientConfiguration extends SmithyResolvedConfiguration<HandlerOptions>,
> implements IClient<ClientInput, ClientOutput, ResolvedClientConfiguration>
{
public middlewareStack: MiddlewareStack<ClientInput, ClientOutput> = constructStack<ClientInput, ClientOutput>({
onChange: () => {
delete this.handlers;
},
});
public middlewareStack: MiddlewareStack<ClientInput, ClientOutput> = constructStack<ClientInput, ClientOutput>();
/**
* May be used to cache the resolved handler function for a Command class.
*/
private handlers?: WeakMap<Function, Handler<any, any>> | undefined;
private configRef?: ResolvedClientConfiguration | undefined;

constructor(public readonly config: ResolvedClientConfiguration) {
this.configRef = this.config;
}
constructor(public readonly config: ResolvedClientConfiguration) {}

send<InputType extends ClientInput, OutputType extends ClientOutput>(
command: Command<ClientInput, InputType, ClientOutput, OutputType, SmithyResolvedConfiguration<HandlerOptions>>,
Expand All @@ -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<any, any>;

Expand All @@ -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) {
Expand Down

0 comments on commit 78c26dd

Please sign in to comment.