Skip to content

Commit fc930f6

Browse files
authoredMar 19, 2025··
Merge pull request #1654 from yasaichi/remove-multiple-span-end-calls
fix: error Operation attempted on ended Span

File tree

1 file changed

+179
-207
lines changed

1 file changed

+179
-207
lines changed
 

‎packages/http/fetch/src/fetchRequestAdapter.ts

+179-207
Original file line numberDiff line numberDiff line change
@@ -72,54 +72,50 @@ export class FetchRequestAdapter implements RequestAdapter {
7272
throw new Error("requestInfo cannot be null");
7373
}
7474
return this.startTracingSpan(requestInfo, "sendCollectionOfPrimitive", async (span) => {
75-
try {
76-
const response = await this.getHttpResponseMessage(requestInfo, span);
77-
const responseHandler = this.getResponseHandler(requestInfo);
78-
if (responseHandler) {
79-
span.addEvent(FetchRequestAdapter.eventResponseHandlerInvokedKey);
80-
return await responseHandler.handleResponse(response, errorMappings);
81-
} else {
82-
try {
83-
await this.throwIfFailedResponse(response, errorMappings, span);
84-
if (this.shouldReturnUndefined(response)) return undefined;
85-
switch (responseType) {
86-
case "string":
87-
case "number":
88-
case "boolean":
89-
case "Date":
90-
// eslint-disable-next-line no-case-declarations
91-
const rootNode = await this.getRootParseNode(response);
92-
return trace.getTracer(this.observabilityOptions.getTracerInstrumentationName()).startActiveSpan(`getCollectionOf${responseType}Value`, (deserializeSpan) => {
93-
try {
94-
span.setAttribute(FetchRequestAdapter.responseTypeAttributeKey, responseType);
95-
if (responseType === "string") {
96-
return rootNode.getCollectionOfPrimitiveValues<string>() as unknown as ResponseType[];
97-
} else if (responseType === "number") {
98-
return rootNode.getCollectionOfPrimitiveValues<number>() as unknown as ResponseType[];
99-
} else if (responseType === "boolean") {
100-
return rootNode.getCollectionOfPrimitiveValues<boolean>() as unknown as ResponseType[];
101-
} else if (responseType === "Date") {
102-
return rootNode.getCollectionOfPrimitiveValues<Date>() as unknown as ResponseType[];
103-
} else if (responseType === "Duration") {
104-
return rootNode.getCollectionOfPrimitiveValues<Duration>() as unknown as ResponseType[];
105-
} else if (responseType === "DateOnly") {
106-
return rootNode.getCollectionOfPrimitiveValues<DateOnly>() as unknown as ResponseType[];
107-
} else if (responseType === "TimeOnly") {
108-
return rootNode.getCollectionOfPrimitiveValues<TimeOnly>() as unknown as ResponseType[];
109-
} else {
110-
throw new Error("unexpected type to deserialize");
111-
}
112-
} finally {
113-
deserializeSpan.end();
75+
const response = await this.getHttpResponseMessage(requestInfo, span);
76+
const responseHandler = this.getResponseHandler(requestInfo);
77+
if (responseHandler) {
78+
span.addEvent(FetchRequestAdapter.eventResponseHandlerInvokedKey);
79+
return await responseHandler.handleResponse(response, errorMappings);
80+
} else {
81+
try {
82+
await this.throwIfFailedResponse(response, errorMappings, span);
83+
if (this.shouldReturnUndefined(response)) return undefined;
84+
switch (responseType) {
85+
case "string":
86+
case "number":
87+
case "boolean":
88+
case "Date":
89+
// eslint-disable-next-line no-case-declarations
90+
const rootNode = await this.getRootParseNode(response);
91+
return trace.getTracer(this.observabilityOptions.getTracerInstrumentationName()).startActiveSpan(`getCollectionOf${responseType}Value`, (deserializeSpan) => {
92+
try {
93+
span.setAttribute(FetchRequestAdapter.responseTypeAttributeKey, responseType);
94+
if (responseType === "string") {
95+
return rootNode.getCollectionOfPrimitiveValues<string>() as unknown as ResponseType[];
96+
} else if (responseType === "number") {
97+
return rootNode.getCollectionOfPrimitiveValues<number>() as unknown as ResponseType[];
98+
} else if (responseType === "boolean") {
99+
return rootNode.getCollectionOfPrimitiveValues<boolean>() as unknown as ResponseType[];
100+
} else if (responseType === "Date") {
101+
return rootNode.getCollectionOfPrimitiveValues<Date>() as unknown as ResponseType[];
102+
} else if (responseType === "Duration") {
103+
return rootNode.getCollectionOfPrimitiveValues<Duration>() as unknown as ResponseType[];
104+
} else if (responseType === "DateOnly") {
105+
return rootNode.getCollectionOfPrimitiveValues<DateOnly>() as unknown as ResponseType[];
106+
} else if (responseType === "TimeOnly") {
107+
return rootNode.getCollectionOfPrimitiveValues<TimeOnly>() as unknown as ResponseType[];
108+
} else {
109+
throw new Error("unexpected type to deserialize");
114110
}
115-
});
116-
}
117-
} finally {
118-
await this.purgeResponseBody(response);
111+
} finally {
112+
deserializeSpan.end();
113+
}
114+
});
119115
}
116+
} finally {
117+
await this.purgeResponseBody(response);
120118
}
121-
} finally {
122-
span.end();
123119
}
124120
});
125121
};
@@ -128,32 +124,28 @@ export class FetchRequestAdapter implements RequestAdapter {
128124
throw new Error("requestInfo cannot be null");
129125
}
130126
return this.startTracingSpan(requestInfo, "sendCollection", async (span) => {
131-
try {
132-
const response = await this.getHttpResponseMessage(requestInfo, span);
133-
const responseHandler = this.getResponseHandler(requestInfo);
134-
if (responseHandler) {
135-
span.addEvent(FetchRequestAdapter.eventResponseHandlerInvokedKey);
136-
return await responseHandler.handleResponse(response, errorMappings);
137-
} else {
138-
try {
139-
await this.throwIfFailedResponse(response, errorMappings, span);
140-
if (this.shouldReturnUndefined(response)) return undefined;
141-
const rootNode = await this.getRootParseNode(response);
142-
return trace.getTracer(this.observabilityOptions.getTracerInstrumentationName()).startActiveSpan("getCollectionOfObjectValues", (deserializeSpan) => {
143-
try {
144-
const result = rootNode.getCollectionOfObjectValues(deserialization);
145-
span.setAttribute(FetchRequestAdapter.responseTypeAttributeKey, "object[]");
146-
return result as unknown as ModelType[];
147-
} finally {
148-
deserializeSpan.end();
149-
}
150-
});
151-
} finally {
152-
await this.purgeResponseBody(response);
153-
}
127+
const response = await this.getHttpResponseMessage(requestInfo, span);
128+
const responseHandler = this.getResponseHandler(requestInfo);
129+
if (responseHandler) {
130+
span.addEvent(FetchRequestAdapter.eventResponseHandlerInvokedKey);
131+
return await responseHandler.handleResponse(response, errorMappings);
132+
} else {
133+
try {
134+
await this.throwIfFailedResponse(response, errorMappings, span);
135+
if (this.shouldReturnUndefined(response)) return undefined;
136+
const rootNode = await this.getRootParseNode(response);
137+
return trace.getTracer(this.observabilityOptions.getTracerInstrumentationName()).startActiveSpan("getCollectionOfObjectValues", (deserializeSpan) => {
138+
try {
139+
const result = rootNode.getCollectionOfObjectValues(deserialization);
140+
span.setAttribute(FetchRequestAdapter.responseTypeAttributeKey, "object[]");
141+
return result as unknown as ModelType[];
142+
} finally {
143+
deserializeSpan.end();
144+
}
145+
});
146+
} finally {
147+
await this.purgeResponseBody(response);
154148
}
155-
} finally {
156-
span.end();
157149
}
158150
});
159151
};
@@ -175,32 +167,28 @@ export class FetchRequestAdapter implements RequestAdapter {
175167
throw new Error("requestInfo cannot be null");
176168
}
177169
return this.startTracingSpan(requestInfo, "send", async (span) => {
178-
try {
179-
const response = await this.getHttpResponseMessage(requestInfo, span);
180-
const responseHandler = this.getResponseHandler(requestInfo);
181-
if (responseHandler) {
182-
span.addEvent(FetchRequestAdapter.eventResponseHandlerInvokedKey);
183-
return await responseHandler.handleResponse(response, errorMappings);
184-
} else {
185-
try {
186-
await this.throwIfFailedResponse(response, errorMappings, span);
187-
if (this.shouldReturnUndefined(response)) return undefined;
188-
const rootNode = await this.getRootParseNode(response);
189-
return trace.getTracer(this.observabilityOptions.getTracerInstrumentationName()).startActiveSpan("getObjectValue", (deserializeSpan) => {
190-
try {
191-
span.setAttribute(FetchRequestAdapter.responseTypeAttributeKey, "object");
192-
const result = rootNode.getObjectValue(deserializer);
193-
return result as unknown as ModelType;
194-
} finally {
195-
deserializeSpan.end();
196-
}
197-
});
198-
} finally {
199-
await this.purgeResponseBody(response);
200-
}
170+
const response = await this.getHttpResponseMessage(requestInfo, span);
171+
const responseHandler = this.getResponseHandler(requestInfo);
172+
if (responseHandler) {
173+
span.addEvent(FetchRequestAdapter.eventResponseHandlerInvokedKey);
174+
return await responseHandler.handleResponse(response, errorMappings);
175+
} else {
176+
try {
177+
await this.throwIfFailedResponse(response, errorMappings, span);
178+
if (this.shouldReturnUndefined(response)) return undefined;
179+
const rootNode = await this.getRootParseNode(response);
180+
return trace.getTracer(this.observabilityOptions.getTracerInstrumentationName()).startActiveSpan("getObjectValue", (deserializeSpan) => {
181+
try {
182+
span.setAttribute(FetchRequestAdapter.responseTypeAttributeKey, "object");
183+
const result = rootNode.getObjectValue(deserializer);
184+
return result as unknown as ModelType;
185+
} finally {
186+
deserializeSpan.end();
187+
}
188+
});
189+
} finally {
190+
await this.purgeResponseBody(response);
201191
}
202-
} finally {
203-
span.end();
204192
}
205193
}) as Promise<ModelType>;
206194
};
@@ -209,59 +197,55 @@ export class FetchRequestAdapter implements RequestAdapter {
209197
throw new Error("requestInfo cannot be null");
210198
}
211199
return this.startTracingSpan(requestInfo, "sendPrimitive", async (span) => {
212-
try {
213-
const response = await this.getHttpResponseMessage(requestInfo, span);
214-
const responseHandler = this.getResponseHandler(requestInfo);
215-
if (responseHandler) {
216-
span.addEvent(FetchRequestAdapter.eventResponseHandlerInvokedKey);
217-
return await responseHandler.handleResponse(response, errorMappings);
218-
} else {
219-
try {
220-
await this.throwIfFailedResponse(response, errorMappings, span);
221-
if (this.shouldReturnUndefined(response)) return undefined;
222-
switch (responseType) {
223-
case "ArrayBuffer":
224-
if (!response.body) {
225-
return undefined;
226-
}
227-
return (await response.arrayBuffer()) as unknown as ResponseType;
228-
case "string":
229-
case "number":
230-
case "boolean":
231-
case "Date":
232-
// eslint-disable-next-line no-case-declarations
233-
const rootNode = await this.getRootParseNode(response);
234-
span.setAttribute(FetchRequestAdapter.responseTypeAttributeKey, responseType);
235-
return trace.getTracer(this.observabilityOptions.getTracerInstrumentationName()).startActiveSpan(`get${responseType}Value`, (deserializeSpan) => {
236-
try {
237-
if (responseType === "string") {
238-
return rootNode.getStringValue() as unknown as ResponseType;
239-
} else if (responseType === "number") {
240-
return rootNode.getNumberValue() as unknown as ResponseType;
241-
} else if (responseType === "boolean") {
242-
return rootNode.getBooleanValue() as unknown as ResponseType;
243-
} else if (responseType === "Date") {
244-
return rootNode.getDateValue() as unknown as ResponseType;
245-
} else if (responseType === "Duration") {
246-
return rootNode.getDurationValue() as unknown as ResponseType;
247-
} else if (responseType === "DateOnly") {
248-
return rootNode.getDateOnlyValue() as unknown as ResponseType;
249-
} else if (responseType === "TimeOnly") {
250-
return rootNode.getTimeOnlyValue() as unknown as ResponseType;
251-
} else {
252-
throw new Error("unexpected type to deserialize");
253-
}
254-
} finally {
255-
deserializeSpan.end();
200+
const response = await this.getHttpResponseMessage(requestInfo, span);
201+
const responseHandler = this.getResponseHandler(requestInfo);
202+
if (responseHandler) {
203+
span.addEvent(FetchRequestAdapter.eventResponseHandlerInvokedKey);
204+
return await responseHandler.handleResponse(response, errorMappings);
205+
} else {
206+
try {
207+
await this.throwIfFailedResponse(response, errorMappings, span);
208+
if (this.shouldReturnUndefined(response)) return undefined;
209+
switch (responseType) {
210+
case "ArrayBuffer":
211+
if (!response.body) {
212+
return undefined;
213+
}
214+
return (await response.arrayBuffer()) as unknown as ResponseType;
215+
case "string":
216+
case "number":
217+
case "boolean":
218+
case "Date":
219+
// eslint-disable-next-line no-case-declarations
220+
const rootNode = await this.getRootParseNode(response);
221+
span.setAttribute(FetchRequestAdapter.responseTypeAttributeKey, responseType);
222+
return trace.getTracer(this.observabilityOptions.getTracerInstrumentationName()).startActiveSpan(`get${responseType}Value`, (deserializeSpan) => {
223+
try {
224+
if (responseType === "string") {
225+
return rootNode.getStringValue() as unknown as ResponseType;
226+
} else if (responseType === "number") {
227+
return rootNode.getNumberValue() as unknown as ResponseType;
228+
} else if (responseType === "boolean") {
229+
return rootNode.getBooleanValue() as unknown as ResponseType;
230+
} else if (responseType === "Date") {
231+
return rootNode.getDateValue() as unknown as ResponseType;
232+
} else if (responseType === "Duration") {
233+
return rootNode.getDurationValue() as unknown as ResponseType;
234+
} else if (responseType === "DateOnly") {
235+
return rootNode.getDateOnlyValue() as unknown as ResponseType;
236+
} else if (responseType === "TimeOnly") {
237+
return rootNode.getTimeOnlyValue() as unknown as ResponseType;
238+
} else {
239+
throw new Error("unexpected type to deserialize");
256240
}
257-
});
258-
}
259-
} finally {
260-
await this.purgeResponseBody(response);
241+
} finally {
242+
deserializeSpan.end();
243+
}
244+
});
261245
}
246+
} finally {
247+
await this.purgeResponseBody(response);
262248
}
263-
} finally {
264-
span.end();
265249
}
266250
});
267251
};
@@ -270,20 +254,16 @@ export class FetchRequestAdapter implements RequestAdapter {
270254
throw new Error("requestInfo cannot be null");
271255
}
272256
return this.startTracingSpan(requestInfo, "sendNoResponseContent", async (span) => {
257+
const response = await this.getHttpResponseMessage(requestInfo, span);
258+
const responseHandler = this.getResponseHandler(requestInfo);
259+
if (responseHandler) {
260+
span.addEvent(FetchRequestAdapter.eventResponseHandlerInvokedKey);
261+
return await responseHandler.handleResponse(response, errorMappings);
262+
}
273263
try {
274-
const response = await this.getHttpResponseMessage(requestInfo, span);
275-
const responseHandler = this.getResponseHandler(requestInfo);
276-
if (responseHandler) {
277-
span.addEvent(FetchRequestAdapter.eventResponseHandlerInvokedKey);
278-
return await responseHandler.handleResponse(response, errorMappings);
279-
}
280-
try {
281-
await this.throwIfFailedResponse(response, errorMappings, span);
282-
} finally {
283-
await this.purgeResponseBody(response);
284-
}
264+
await this.throwIfFailedResponse(response, errorMappings, span);
285265
} finally {
286-
span.end();
266+
await this.purgeResponseBody(response);
287267
}
288268
});
289269
};
@@ -292,32 +272,28 @@ export class FetchRequestAdapter implements RequestAdapter {
292272
throw new Error("requestInfo cannot be null");
293273
}
294274
return this.startTracingSpan(requestInfo, "sendEnum", async (span) => {
295-
try {
296-
const response = await this.getHttpResponseMessage(requestInfo, span);
297-
const responseHandler = this.getResponseHandler(requestInfo);
298-
if (responseHandler) {
299-
span.addEvent(FetchRequestAdapter.eventResponseHandlerInvokedKey);
300-
return await responseHandler.handleResponse(response, errorMappings);
301-
} else {
302-
try {
303-
await this.throwIfFailedResponse(response, errorMappings, span);
304-
if (this.shouldReturnUndefined(response)) return undefined;
305-
const rootNode = await this.getRootParseNode(response);
306-
return trace.getTracer(this.observabilityOptions.getTracerInstrumentationName()).startActiveSpan("getEnumValue", (deserializeSpan) => {
307-
try {
308-
span.setAttribute(FetchRequestAdapter.responseTypeAttributeKey, "enum");
309-
const result = rootNode.getEnumValue(enumObject);
310-
return result as EnumObject[keyof EnumObject];
311-
} finally {
312-
deserializeSpan.end();
313-
}
314-
});
315-
} finally {
316-
await this.purgeResponseBody(response);
317-
}
275+
const response = await this.getHttpResponseMessage(requestInfo, span);
276+
const responseHandler = this.getResponseHandler(requestInfo);
277+
if (responseHandler) {
278+
span.addEvent(FetchRequestAdapter.eventResponseHandlerInvokedKey);
279+
return await responseHandler.handleResponse(response, errorMappings);
280+
} else {
281+
try {
282+
await this.throwIfFailedResponse(response, errorMappings, span);
283+
if (this.shouldReturnUndefined(response)) return undefined;
284+
const rootNode = await this.getRootParseNode(response);
285+
return trace.getTracer(this.observabilityOptions.getTracerInstrumentationName()).startActiveSpan("getEnumValue", (deserializeSpan) => {
286+
try {
287+
span.setAttribute(FetchRequestAdapter.responseTypeAttributeKey, "enum");
288+
const result = rootNode.getEnumValue(enumObject);
289+
return result as EnumObject[keyof EnumObject];
290+
} finally {
291+
deserializeSpan.end();
292+
}
293+
});
294+
} finally {
295+
await this.purgeResponseBody(response);
318296
}
319-
} finally {
320-
span.end();
321297
}
322298
}) as Promise<EnumObject[keyof EnumObject]>;
323299
};
@@ -326,32 +302,28 @@ export class FetchRequestAdapter implements RequestAdapter {
326302
throw new Error("requestInfo cannot be null");
327303
}
328304
return this.startTracingSpan(requestInfo, "sendCollectionOfEnum", async (span) => {
329-
try {
330-
const response = await this.getHttpResponseMessage(requestInfo, span);
331-
const responseHandler = this.getResponseHandler(requestInfo);
332-
if (responseHandler) {
333-
span.addEvent(FetchRequestAdapter.eventResponseHandlerInvokedKey);
334-
return await responseHandler.handleResponse(response, errorMappings);
335-
} else {
336-
try {
337-
await this.throwIfFailedResponse(response, errorMappings, span);
338-
if (this.shouldReturnUndefined(response)) return undefined;
339-
const rootNode = await this.getRootParseNode(response);
340-
return trace.getTracer(this.observabilityOptions.getTracerInstrumentationName()).startActiveSpan("getCollectionOfEnumValues", (deserializeSpan) => {
341-
try {
342-
const result = rootNode.getCollectionOfEnumValues(enumObject);
343-
span.setAttribute(FetchRequestAdapter.responseTypeAttributeKey, "enum[]");
344-
return result as unknown as EnumObject[keyof EnumObject][];
345-
} finally {
346-
deserializeSpan.end();
347-
}
348-
});
349-
} finally {
350-
await this.purgeResponseBody(response);
351-
}
305+
const response = await this.getHttpResponseMessage(requestInfo, span);
306+
const responseHandler = this.getResponseHandler(requestInfo);
307+
if (responseHandler) {
308+
span.addEvent(FetchRequestAdapter.eventResponseHandlerInvokedKey);
309+
return await responseHandler.handleResponse(response, errorMappings);
310+
} else {
311+
try {
312+
await this.throwIfFailedResponse(response, errorMappings, span);
313+
if (this.shouldReturnUndefined(response)) return undefined;
314+
const rootNode = await this.getRootParseNode(response);
315+
return trace.getTracer(this.observabilityOptions.getTracerInstrumentationName()).startActiveSpan("getCollectionOfEnumValues", (deserializeSpan) => {
316+
try {
317+
const result = rootNode.getCollectionOfEnumValues(enumObject);
318+
span.setAttribute(FetchRequestAdapter.responseTypeAttributeKey, "enum[]");
319+
return result as unknown as EnumObject[keyof EnumObject][];
320+
} finally {
321+
deserializeSpan.end();
322+
}
323+
});
324+
} finally {
325+
await this.purgeResponseBody(response);
352326
}
353-
} finally {
354-
span.end();
355327
}
356328
});
357329
};

0 commit comments

Comments
 (0)
Please sign in to comment.