Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/large-badgers-cheer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@smithy/types": minor
"@smithy/core": minor
---

add MetricsRecorder support to clients: a call-site recorder passed to client.send is placed on the handler execution context for middleware to consume
Original file line number Diff line number Diff line change
Expand Up @@ -90,4 +90,32 @@ describe(Command.name, () => {
requestTimeout: 5000,
});
});

it("places the call-site recorder on the handler execution context", async () => {
let capturedContext: any;

class MyCommand extends Command.classBuilder<any, any, any, any, any>()
.m(function () {
return [];
})
.s("MyClient", "MyOp", {})
.n("MyClient", "MyOp")
.f()
.ser(async (_) => ({ ..._, headers: {}, method: "POST", protocol: "https:", hostname: "localhost", path: "/" }))
.de(async (_) => ({ $metadata: {} }))
.build() {}

const recorder = { addCount: vi.fn() };
const cmd = new MyCommand({});
cmd.resolveMiddleware(
{ concat: () => ({ resolve: (fn: any, ctx: any) => ((capturedContext = ctx), fn) }) } as any,
{
logger: {} as any,
requestHandler: { handle: vi.fn().mockResolvedValue({ response: {} }) },
},
{ recorder }
);

expect(capturedContext.recorder).toBe(recorder);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ export abstract class Command<
...smithyContext,
},
...additionalContext,
recorder: options?.recorder,
};
const { requestHandler } = configuration;
let requestOptions = options ?? {};
Expand Down
9 changes: 9 additions & 0 deletions packages/types/src/middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { Command } from "./command";
import type { EndpointV2 } from "./endpoint";
import type { SmithyFeatures } from "./feature-ids";
import type { Logger } from "./logger";
import type { MetricsRecorder } from "./metrics";
import type { UserAgent } from "./util";

/**
Expand Down Expand Up @@ -584,6 +585,14 @@ export interface HandlerExecutionContext {
[key: string]: unknown;
};

/**
* A per-request {@link MetricsRecorder} supplied at the `client.send(command, { recorder })`
* call site. When present, a metrics middleware records into this recorder instead of one
* minted from a factory, letting a caller (e.g. a server handler) fold the client's request
* metrics into its own.
*/
recorder?: MetricsRecorder<any>;

/**
* Set by some operations which instructs the retry behavior to backoff
* after a failed request even when no further retry (of the same request) is expected.
Expand Down
28 changes: 18 additions & 10 deletions private/my-local-model-schema/src/XYZService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import { type WaiterResult, createAggregatedClient } from "@smithy/core/client";
import type {
HttpHandlerOptions as __HttpHandlerOptions,
MetricsRecorder as __MetricsRecorder,
PaginationConfiguration,
Paginator,
WaiterConfiguration,
Expand Down Expand Up @@ -58,21 +59,28 @@ const waiters = {
waitUntilNumbersWhatDoTheyDoAnyway,
};

/**
* @public
*/
export interface XYZServiceRequestOptions extends __HttpHandlerOptions {
recorder?: __MetricsRecorder<any>;
}

export interface XYZService {
/**
* @see {@link HttpLabelCommandCommand}
*/
httpLabelCommand(
args: HttpLabelCommandCommandInput,
options?: __HttpHandlerOptions
options?: XYZServiceRequestOptions
): Promise<HttpLabelCommandCommandOutput>;
httpLabelCommand(
args: HttpLabelCommandCommandInput,
cb: (err: any, data?: HttpLabelCommandCommandOutput) => void
): void;
httpLabelCommand(
args: HttpLabelCommandCommandInput,
options: __HttpHandlerOptions,
options: XYZServiceRequestOptions,
cb: (err: any, data?: HttpLabelCommandCommandOutput) => void
): void;

Expand All @@ -82,15 +90,15 @@ export interface XYZService {
camelCaseOperation(): Promise<CamelCaseOperationCommandOutput>;
camelCaseOperation(
args: CamelCaseOperationCommandInput,
options?: __HttpHandlerOptions
options?: XYZServiceRequestOptions
): Promise<CamelCaseOperationCommandOutput>;
camelCaseOperation(
args: CamelCaseOperationCommandInput,
cb: (err: any, data?: CamelCaseOperationCommandOutput) => void
): void;
camelCaseOperation(
args: CamelCaseOperationCommandInput,
options: __HttpHandlerOptions,
options: XYZServiceRequestOptions,
cb: (err: any, data?: CamelCaseOperationCommandOutput) => void
): void;

Expand All @@ -100,15 +108,15 @@ export interface XYZService {
getNumbers(): Promise<GetNumbersCommandOutput>;
getNumbers(
args: GetNumbersCommandInput,
options?: __HttpHandlerOptions
options?: XYZServiceRequestOptions
): Promise<GetNumbersCommandOutput>;
getNumbers(
args: GetNumbersCommandInput,
cb: (err: any, data?: GetNumbersCommandOutput) => void
): void;
getNumbers(
args: GetNumbersCommandInput,
options: __HttpHandlerOptions,
options: XYZServiceRequestOptions,
cb: (err: any, data?: GetNumbersCommandOutput) => void
): void;

Expand All @@ -117,15 +125,15 @@ export interface XYZService {
*/
hostPrefixOperation(
args: HostPrefixOperationCommandInput,
options?: __HttpHandlerOptions
options?: XYZServiceRequestOptions
): Promise<HostPrefixOperationCommandOutput>;
hostPrefixOperation(
args: HostPrefixOperationCommandInput,
cb: (err: any, data?: HostPrefixOperationCommandOutput) => void
): void;
hostPrefixOperation(
args: HostPrefixOperationCommandInput,
options: __HttpHandlerOptions,
options: XYZServiceRequestOptions,
cb: (err: any, data?: HostPrefixOperationCommandOutput) => void
): void;

Expand All @@ -135,15 +143,15 @@ export interface XYZService {
tradeEventStream(): Promise<TradeEventStreamCommandOutput>;
tradeEventStream(
args: TradeEventStreamCommandInput,
options?: __HttpHandlerOptions
options?: XYZServiceRequestOptions
): Promise<TradeEventStreamCommandOutput>;
tradeEventStream(
args: TradeEventStreamCommandInput,
cb: (err: any, data?: TradeEventStreamCommandOutput) => void
): void;
tradeEventStream(
args: TradeEventStreamCommandInput,
options: __HttpHandlerOptions,
options: XYZServiceRequestOptions,
cb: (err: any, data?: TradeEventStreamCommandOutput) => void
): void;

Expand Down
28 changes: 18 additions & 10 deletions private/my-local-model/src/XYZService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import { type WaiterResult, createAggregatedClient } from "@smithy/core/client";
import type {
HttpHandlerOptions as __HttpHandlerOptions,
MetricsRecorder as __MetricsRecorder,
PaginationConfiguration,
Paginator,
WaiterConfiguration,
Expand Down Expand Up @@ -58,21 +59,28 @@ const waiters = {
waitUntilNumbersWhatDoTheyDoAnyway,
};

/**
* @public
*/
export interface XYZServiceRequestOptions extends __HttpHandlerOptions {
recorder?: __MetricsRecorder<any>;
}

export interface XYZService {
/**
* @see {@link HttpLabelCommandCommand}
*/
httpLabelCommand(
args: HttpLabelCommandCommandInput,
options?: __HttpHandlerOptions
options?: XYZServiceRequestOptions
): Promise<HttpLabelCommandCommandOutput>;
httpLabelCommand(
args: HttpLabelCommandCommandInput,
cb: (err: any, data?: HttpLabelCommandCommandOutput) => void
): void;
httpLabelCommand(
args: HttpLabelCommandCommandInput,
options: __HttpHandlerOptions,
options: XYZServiceRequestOptions,
cb: (err: any, data?: HttpLabelCommandCommandOutput) => void
): void;

Expand All @@ -82,15 +90,15 @@ export interface XYZService {
camelCaseOperation(): Promise<CamelCaseOperationCommandOutput>;
camelCaseOperation(
args: CamelCaseOperationCommandInput,
options?: __HttpHandlerOptions
options?: XYZServiceRequestOptions
): Promise<CamelCaseOperationCommandOutput>;
camelCaseOperation(
args: CamelCaseOperationCommandInput,
cb: (err: any, data?: CamelCaseOperationCommandOutput) => void
): void;
camelCaseOperation(
args: CamelCaseOperationCommandInput,
options: __HttpHandlerOptions,
options: XYZServiceRequestOptions,
cb: (err: any, data?: CamelCaseOperationCommandOutput) => void
): void;

Expand All @@ -100,15 +108,15 @@ export interface XYZService {
getNumbers(): Promise<GetNumbersCommandOutput>;
getNumbers(
args: GetNumbersCommandInput,
options?: __HttpHandlerOptions
options?: XYZServiceRequestOptions
): Promise<GetNumbersCommandOutput>;
getNumbers(
args: GetNumbersCommandInput,
cb: (err: any, data?: GetNumbersCommandOutput) => void
): void;
getNumbers(
args: GetNumbersCommandInput,
options: __HttpHandlerOptions,
options: XYZServiceRequestOptions,
cb: (err: any, data?: GetNumbersCommandOutput) => void
): void;

Expand All @@ -117,15 +125,15 @@ export interface XYZService {
*/
hostPrefixOperation(
args: HostPrefixOperationCommandInput,
options?: __HttpHandlerOptions
options?: XYZServiceRequestOptions
): Promise<HostPrefixOperationCommandOutput>;
hostPrefixOperation(
args: HostPrefixOperationCommandInput,
cb: (err: any, data?: HostPrefixOperationCommandOutput) => void
): void;
hostPrefixOperation(
args: HostPrefixOperationCommandInput,
options: __HttpHandlerOptions,
options: XYZServiceRequestOptions,
cb: (err: any, data?: HostPrefixOperationCommandOutput) => void
): void;

Expand All @@ -135,15 +143,15 @@ export interface XYZService {
tradeEventStream(): Promise<TradeEventStreamCommandOutput>;
tradeEventStream(
args: TradeEventStreamCommandInput,
options?: __HttpHandlerOptions
options?: XYZServiceRequestOptions
): Promise<TradeEventStreamCommandOutput>;
tradeEventStream(
args: TradeEventStreamCommandInput,
cb: (err: any, data?: TradeEventStreamCommandOutput) => void
): void;
tradeEventStream(
args: TradeEventStreamCommandInput,
options: __HttpHandlerOptions,
options: XYZServiceRequestOptions,
cb: (err: any, data?: TradeEventStreamCommandOutput) => void
): void;

Expand Down
Loading