From 4b5a468f3bcf98052cc4f658bb1b67c02b92c58d Mon Sep 17 00:00:00 2001 From: jsl517 Date: Wed, 4 Mar 2026 14:28:49 -0800 Subject: [PATCH 1/4] Fix exporter timeout config and default enableBaggage to false - Agent365Exporter now uses the configured exporterTimeoutMilliseconds instead of a hardcoded 30s constant for HTTP request timeouts - ObservabilityHostingManager.enableBaggage defaults to false (breaking); callers must opt in explicitly Co-Authored-By: Claude Opus 4.6 --- CHANGELOG.md | 4 ++++ .../middleware/ObservabilityHostingManager.ts | 4 ++-- .../src/tracing/exporter/Agent365Exporter.ts | 3 +-- .../observability-hosting-manager.test.ts | 20 ++++++++++++------- 4 files changed, 20 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ccacef0d..40a78e03 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - **OutputLoggingMiddleware**: Middleware that creates OutputScope spans for outgoing messages with lazy parent span linking via `A365_PARENT_SPAN_KEY`. - **ObservabilityHostingManager**: Manager for configuring hosting-layer observability middleware with `ObservabilityHostingOptions`. +### Fixed +- **Agent365Exporter**: `exporterTimeoutMilliseconds` option is now respected for HTTP requests. Previously the exporter used a hardcoded 30-second timeout, ignoring the configured value. + ### Changed +- **ObservabilityHostingManager**: `enableBaggage` option now defaults to `false` (was `true`). Callers must explicitly set `enableBaggage: true` to register the BaggageMiddleware. - `InferenceScope.recordInputMessages()` / `recordOutputMessages()` now use JSON array format instead of comma-separated strings. - `InvokeAgentScope.recordInputMessages()` / `recordOutputMessages()` now use JSON array format instead of comma-separated strings. diff --git a/packages/agents-a365-observability-hosting/src/middleware/ObservabilityHostingManager.ts b/packages/agents-a365-observability-hosting/src/middleware/ObservabilityHostingManager.ts index a5f05803..5d9eeb32 100644 --- a/packages/agents-a365-observability-hosting/src/middleware/ObservabilityHostingManager.ts +++ b/packages/agents-a365-observability-hosting/src/middleware/ObservabilityHostingManager.ts @@ -10,7 +10,7 @@ import { OutputLoggingMiddleware } from './OutputLoggingMiddleware'; * Configuration options for the hosting observability layer. */ export interface ObservabilityHostingOptions { - /** Enable baggage propagation middleware. Defaults to true. */ + /** Enable baggage propagation middleware. Defaults to false. */ enableBaggage?: boolean; /** Enable output logging middleware for tracing outgoing messages. Defaults to false. */ @@ -42,7 +42,7 @@ export class ObservabilityHostingManager { return; } - const enableBaggage = options.enableBaggage !== false; + const enableBaggage = options.enableBaggage === true; const enableOutputLogging = options.enableOutputLogging === true; if (enableBaggage) { diff --git a/packages/agents-a365-observability/src/tracing/exporter/Agent365Exporter.ts b/packages/agents-a365-observability/src/tracing/exporter/Agent365Exporter.ts index 0839f07b..efe75e88 100644 --- a/packages/agents-a365-observability/src/tracing/exporter/Agent365Exporter.ts +++ b/packages/agents-a365-observability/src/tracing/exporter/Agent365Exporter.ts @@ -24,7 +24,6 @@ import logger, { formatError } from '../../utils/logging'; import { Agent365ExporterOptions } from './Agent365ExporterOptions'; import { ExporterEventNames } from './ExporterEventNames'; -const DEFAULT_HTTP_TIMEOUT_SECONDS = 30000; // 30 seconds in ms const DEFAULT_MAX_RETRIES = 3; interface OTLPExportRequest { @@ -247,7 +246,7 @@ export class Agent365Exporter implements SpanExporter { method: 'POST', headers, body, - signal: AbortSignal.timeout(DEFAULT_HTTP_TIMEOUT_SECONDS) + signal: AbortSignal.timeout(this.options.exporterTimeoutMilliseconds) }); correlationId = response?.headers?.get('x-ms-correlation-id') || response?.headers?.get('x-correlation-id') || 'unknown'; diff --git a/tests/observability/extension/hosting/observability-hosting-manager.test.ts b/tests/observability/extension/hosting/observability-hosting-manager.test.ts index 99eae6e3..7b2d5db7 100644 --- a/tests/observability/extension/hosting/observability-hosting-manager.test.ts +++ b/tests/observability/extension/hosting/observability-hosting-manager.test.ts @@ -12,24 +12,30 @@ function mockAdapter() { } describe('ObservabilityHostingManager', () => { - it('registers BaggageMiddleware by default', () => { + it('does not register BaggageMiddleware by default', () => { const adapter = mockAdapter(); new ObservabilityHostingManager().configure(adapter, {}); + expect(adapter.registered).toHaveLength(0); + }); + + it('registers BaggageMiddleware when enableBaggage is true', () => { + const adapter = mockAdapter(); + new ObservabilityHostingManager().configure(adapter, { enableBaggage: true }); expect(adapter.registered).toHaveLength(1); expect(adapter.registered[0]).toBeInstanceOf(BaggageMiddleware); }); - it('registers both middleware when enableOutputLogging is true', () => { + it('registers both middleware when enableBaggage and enableOutputLogging are true', () => { const adapter = mockAdapter(); - new ObservabilityHostingManager().configure(adapter, { enableOutputLogging: true }); + new ObservabilityHostingManager().configure(adapter, { enableBaggage: true, enableOutputLogging: true }); expect(adapter.registered).toHaveLength(2); expect(adapter.registered[0]).toBeInstanceOf(BaggageMiddleware); expect(adapter.registered[1]).toBeInstanceOf(OutputLoggingMiddleware); }); - it('skips BaggageMiddleware when enableBaggage is false', () => { + it('registers only OutputLoggingMiddleware when enableOutputLogging is true and enableBaggage is omitted', () => { const adapter = mockAdapter(); - new ObservabilityHostingManager().configure(adapter, { enableBaggage: false, enableOutputLogging: true }); + new ObservabilityHostingManager().configure(adapter, { enableOutputLogging: true }); expect(adapter.registered).toHaveLength(1); expect(adapter.registered[0]).toBeInstanceOf(OutputLoggingMiddleware); }); @@ -37,8 +43,8 @@ describe('ObservabilityHostingManager', () => { it('subsequent configure calls on same instance are no-ops', () => { const adapter = mockAdapter(); const manager = new ObservabilityHostingManager(); - manager.configure(adapter, { enableOutputLogging: true }); - manager.configure(adapter, { enableOutputLogging: true }); + manager.configure(adapter, { enableBaggage: true, enableOutputLogging: true }); + manager.configure(adapter, { enableBaggage: true, enableOutputLogging: true }); expect(adapter.registered).toHaveLength(2); }); }); From 0ae2f6e24b66291027f15680957a20c2b9d75445 Mon Sep 17 00:00:00 2001 From: jsl517 Date: Thu, 5 Mar 2026 12:52:20 -0800 Subject: [PATCH 2/4] Add httpRequestTimeoutMilliseconds and increase export timeout to 60s - New httpRequestTimeoutMilliseconds option (default 30s) for per-HTTP-request timeout on fetch calls to the observability backend - exporterTimeoutMilliseconds (BatchSpanProcessor deadline) increased to 60s to allow sufficient time for retries across multiple identity groups - Clarified JSDoc to distinguish the two timeout semantics Co-Authored-By: Claude Opus 4.6 --- CHANGELOG.md | 5 ++++- .../src/tracing/exporter/Agent365Exporter.ts | 2 +- .../src/tracing/exporter/Agent365ExporterOptions.ts | 10 +++++++--- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5ca5d21e..5d537201 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,8 +21,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - **OutputLoggingMiddleware**: Middleware that creates OutputScope spans for outgoing messages with lazy parent span linking via `A365_PARENT_SPAN_KEY`. - **ObservabilityHostingManager**: Manager for configuring hosting-layer observability middleware with `ObservabilityHostingOptions`. +### Added +- **Agent365ExporterOptions**: New `httpRequestTimeoutMilliseconds` option (default 30s) controls the per-HTTP-request timeout for backend calls. This is distinct from `exporterTimeoutMilliseconds` which controls the overall BatchSpanProcessor export deadline. + ### Fixed -- **Agent365Exporter**: `exporterTimeoutMilliseconds` option is now respected for HTTP requests. Previously the exporter used a hardcoded 30-second timeout, ignoring the configured value. +- **Agent365ExporterOptions**: `exporterTimeoutMilliseconds` default increased from 30s to 60s to allow sufficient time for retries across multiple identity groups within a single export cycle. ### Changed - **ObservabilityHostingManager**: `enableBaggage` option now defaults to `false` (was `true`). Callers must explicitly set `enableBaggage: true` to register the BaggageMiddleware. diff --git a/packages/agents-a365-observability/src/tracing/exporter/Agent365Exporter.ts b/packages/agents-a365-observability/src/tracing/exporter/Agent365Exporter.ts index efe75e88..b5b8df75 100644 --- a/packages/agents-a365-observability/src/tracing/exporter/Agent365Exporter.ts +++ b/packages/agents-a365-observability/src/tracing/exporter/Agent365Exporter.ts @@ -246,7 +246,7 @@ export class Agent365Exporter implements SpanExporter { method: 'POST', headers, body, - signal: AbortSignal.timeout(this.options.exporterTimeoutMilliseconds) + signal: AbortSignal.timeout(this.options.httpRequestTimeoutMilliseconds) }); correlationId = response?.headers?.get('x-ms-correlation-id') || response?.headers?.get('x-correlation-id') || 'unknown'; diff --git a/packages/agents-a365-observability/src/tracing/exporter/Agent365ExporterOptions.ts b/packages/agents-a365-observability/src/tracing/exporter/Agent365ExporterOptions.ts index 37382bdc..13309bee 100644 --- a/packages/agents-a365-observability/src/tracing/exporter/Agent365ExporterOptions.ts +++ b/packages/agents-a365-observability/src/tracing/exporter/Agent365ExporterOptions.ts @@ -24,7 +24,8 @@ export type TokenResolver = (agentId: string, tenantId: string) => string | null * @property {boolean} [useS2SEndpoint] When true, exporter will POST to the S2S path (/observabilityService/tenants/{tenantId}/agents/{agentId}/traces). * @property {number} maxQueueSize Maximum span queue size before drops occur (passed to BatchSpanProcessor). * @property {number} scheduledDelayMilliseconds Delay between automatic batch flush attempts. - * @property {number} exporterTimeoutMilliseconds Per-export timeout (abort if exceeded). + * @property {number} exporterTimeoutMilliseconds Maximum time (ms) the BatchSpanProcessor waits for the entire export() call to complete before giving up. Covers partitioning, token resolution, and all HTTP retries. + * @property {number} httpRequestTimeoutMilliseconds Timeout (ms) for each individual HTTP request to the observability backend. Applies per fetch() call inside the retry loop; each retry gets a fresh timeout. * @property {number} maxExportBatchSize Maximum number of spans per export batch. */ export class Agent365ExporterOptions { @@ -43,8 +44,11 @@ export class Agent365ExporterOptions { /** Delay (ms) between automatic batch flush attempts. */ public scheduledDelayMilliseconds: number = 5000; - /** Per-export timeout in milliseconds. */ - public exporterTimeoutMilliseconds: number = 30000; + /** Maximum time (ms) the BatchSpanProcessor waits for the entire export() call to complete. */ + public exporterTimeoutMilliseconds: number = 60000; + + /** Timeout (ms) for each individual HTTP request to the observability backend. Each retry attempt gets a fresh timeout. */ + public httpRequestTimeoutMilliseconds: number = 30000; /** Maximum number of spans per export batch. */ public maxExportBatchSize: number = 512; From de176d297813e2831f3ac3945f02fdd6ae310d07 Mon Sep 17 00:00:00 2001 From: jsl517 Date: Fri, 6 Mar 2026 10:46:11 -0800 Subject: [PATCH 3/4] Increase exporterTimeoutMilliseconds default to 90s for BatchSpanProcessor 90s gives more headroom for the aggregate export deadline when multiple identity groups with retries are processed in a single export cycle. Co-Authored-By: Claude Opus 4.6 --- .../src/tracing/exporter/Agent365ExporterOptions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/agents-a365-observability/src/tracing/exporter/Agent365ExporterOptions.ts b/packages/agents-a365-observability/src/tracing/exporter/Agent365ExporterOptions.ts index 13309bee..45523e8c 100644 --- a/packages/agents-a365-observability/src/tracing/exporter/Agent365ExporterOptions.ts +++ b/packages/agents-a365-observability/src/tracing/exporter/Agent365ExporterOptions.ts @@ -45,7 +45,7 @@ export class Agent365ExporterOptions { public scheduledDelayMilliseconds: number = 5000; /** Maximum time (ms) the BatchSpanProcessor waits for the entire export() call to complete. */ - public exporterTimeoutMilliseconds: number = 60000; + public exporterTimeoutMilliseconds: number = 90000; /** Timeout (ms) for each individual HTTP request to the observability backend. Each retry attempt gets a fresh timeout. */ public httpRequestTimeoutMilliseconds: number = 30000; From 36eb9043979fd4422309f8e7b91ca76a42b8fc53 Mon Sep 17 00:00:00 2001 From: jsl517 Date: Fri, 6 Mar 2026 10:46:38 -0800 Subject: [PATCH 4/4] Update CHANGELOG to reflect 90s export timeout default Co-Authored-By: Claude Opus 4.6 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d537201..872e875d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,7 +25,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - **Agent365ExporterOptions**: New `httpRequestTimeoutMilliseconds` option (default 30s) controls the per-HTTP-request timeout for backend calls. This is distinct from `exporterTimeoutMilliseconds` which controls the overall BatchSpanProcessor export deadline. ### Fixed -- **Agent365ExporterOptions**: `exporterTimeoutMilliseconds` default increased from 30s to 60s to allow sufficient time for retries across multiple identity groups within a single export cycle. +- **Agent365ExporterOptions**: `exporterTimeoutMilliseconds` default increased from 30s to 90s to allow sufficient time for retries across multiple identity groups within a single export cycle. ### Changed - **ObservabilityHostingManager**: `enableBaggage` option now defaults to `false` (was `true`). Callers must explicitly set `enableBaggage: true` to register the BaggageMiddleware.