Skip to content

Commit ca1e00e

Browse files
hhoikooclaude
andcommitted
refactor(BA-4330): Scope PR to OTel infrastructure only
Remove GQL resolver span changes (schema.py) and unrelated AgentRow ORM fix (cli/__main__.py) to keep this PR focused on OTel trace propagation infrastructure. GQL spans will be a separate PR. Update the TODO comment on the manual middleware injection workaround to accurately describe the coupling with aiohttp's Application lifecycle. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 7fd2f72 commit ca1e00e

3 files changed

Lines changed: 43 additions & 70 deletions

File tree

src/ai/backend/manager/api/gql_legacy/schema.py

Lines changed: 35 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@
1515
from graphene.types.inputobjecttype import set_input_object_type_default_value
1616
from graphql import GraphQLError, OperationType, Undefined
1717
from graphql.type import GraphQLField
18-
from opentelemetry import trace
19-
from opentelemetry.trace import StatusCode
2018
from sqlalchemy.orm import joinedload, selectinload
2119

2220
from ai.backend.common.clients.valkey_client.valkey_image.client import ValkeyImageClient
@@ -3360,23 +3358,11 @@ def resolve(
33603358
operation_name = (
33613359
info.operation.name.value if info.operation.name is not None else "anonymous"
33623360
)
3363-
tracer = trace.get_tracer(__name__)
3364-
span = tracer.start_span(
3365-
f"gql.{operation_name}.{field_name}",
3366-
attributes={
3367-
"graphql.operation_name": operation_name,
3368-
"graphql.field_name": field_name,
3369-
"graphql.parent_type": parent_type,
3370-
},
3371-
)
33723361

33733362
start = time.perf_counter()
33743363
try:
33753364
res = next(root, info, **args)
33763365
except BackendAIError as e:
3377-
span.record_exception(e)
3378-
span.set_status(StatusCode.ERROR, str(e))
3379-
span.end()
33803366
graph_ctx.metric_observer.observe_request(
33813367
operation_type=operation_type,
33823368
field_name=field_name,
@@ -3387,10 +3373,7 @@ def resolve(
33873373
duration=time.perf_counter() - start,
33883374
)
33893375
raise
3390-
except BaseException as e:
3391-
span.record_exception(e)
3392-
span.set_status(StatusCode.ERROR)
3393-
span.end()
3376+
except BaseException:
33943377
graph_ctx.metric_observer.observe_request(
33953378
operation_type=operation_type,
33963379
field_name=field_name,
@@ -3406,52 +3389,43 @@ def resolve(
34063389

34073390
async def _timed_coro() -> Any:
34083391
coro_start = time.perf_counter()
3409-
with trace.use_span(span, end_on_exit=False):
3410-
try:
3411-
result = await res
3412-
except BackendAIError as e:
3413-
span.record_exception(e)
3414-
span.set_status(StatusCode.ERROR, str(e))
3415-
graph_ctx.metric_observer.observe_request(
3416-
operation_type=operation_type,
3417-
field_name=field_name,
3418-
parent_type=parent_type,
3419-
operation_name=operation_name,
3420-
error_code=e.error_code(),
3421-
success=False,
3422-
duration=time.perf_counter() - coro_start,
3423-
)
3424-
raise
3425-
except BaseException as e:
3426-
span.record_exception(e)
3427-
span.set_status(StatusCode.ERROR)
3428-
graph_ctx.metric_observer.observe_request(
3429-
operation_type=operation_type,
3430-
field_name=field_name,
3431-
parent_type=parent_type,
3432-
operation_name=operation_name,
3433-
error_code=ErrorCode.default(),
3434-
success=False,
3435-
duration=time.perf_counter() - coro_start,
3436-
)
3437-
raise
3438-
else:
3439-
graph_ctx.metric_observer.observe_request(
3440-
operation_type=operation_type,
3441-
field_name=field_name,
3442-
parent_type=parent_type,
3443-
operation_name=operation_name,
3444-
error_code=None,
3445-
success=True,
3446-
duration=time.perf_counter() - coro_start,
3447-
)
3448-
return result
3449-
finally:
3450-
span.end()
3392+
try:
3393+
result = await res
3394+
except BackendAIError as e:
3395+
graph_ctx.metric_observer.observe_request(
3396+
operation_type=operation_type,
3397+
field_name=field_name,
3398+
parent_type=parent_type,
3399+
operation_name=operation_name,
3400+
error_code=e.error_code(),
3401+
success=False,
3402+
duration=time.perf_counter() - coro_start,
3403+
)
3404+
raise
3405+
except BaseException:
3406+
graph_ctx.metric_observer.observe_request(
3407+
operation_type=operation_type,
3408+
field_name=field_name,
3409+
parent_type=parent_type,
3410+
operation_name=operation_name,
3411+
error_code=ErrorCode.default(),
3412+
success=False,
3413+
duration=time.perf_counter() - coro_start,
3414+
)
3415+
raise
3416+
graph_ctx.metric_observer.observe_request(
3417+
operation_type=operation_type,
3418+
field_name=field_name,
3419+
parent_type=parent_type,
3420+
operation_name=operation_name,
3421+
error_code=None,
3422+
success=True,
3423+
duration=time.perf_counter() - coro_start,
3424+
)
3425+
return result
34513426

34523427
return _timed_coro()
34533428

3454-
span.end()
34553429
graph_ctx.metric_observer.observe_request(
34563430
operation_type=operation_type,
34573431
field_name=field_name,

src/ai/backend/manager/cli/__main__.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -265,17 +265,11 @@ def clear_history(cli_ctx: CLIContext, retention: str, vacuum_full: bool) -> Non
265265
from more_itertools import chunked
266266

267267
from ai.backend.common.validators import TimeDuration
268-
from ai.backend.manager.models.agent import AgentRow
269268
from ai.backend.manager.models.error_logs import error_logs
270269
from ai.backend.manager.models.kernel import kernels
271270
from ai.backend.manager.models.session import SessionRow
272271
from ai.backend.manager.models.utils import connect_database, vacuum_db
273272

274-
# AgentRow must be imported to register it with SQLAlchemy's ORM mapper.
275-
# KernelRow (via SessionRow) has a relationship to AgentRow using a string reference,
276-
# which requires AgentRow to be in the mapper registry.
277-
_ = AgentRow
278-
279273
from .context import redis_ctx
280274

281275
log = _get_logger()

src/ai/backend/manager/server.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1777,9 +1777,14 @@ async def webapp_ctx(root_app: web.Application) -> AsyncGenerator[None]:
17771777
jwt_config = root_ctx.config_provider.config.jwt.to_jwt_config()
17781778
root_ctx.jwt_validator = JWTValidator(jwt_config)
17791779

1780-
# Initialize OTel aiohttp instrumentation before the app is frozen.
1781-
# instrument_aiohttp_server() patches the Application class, but since
1782-
# root_app is already instantiated, we must manually inject the middleware.
1780+
# TODO(BA-4330): Remove this manual middleware injection once the manager's
1781+
# setup procedure is decoupled from the aiohttp Application lifecycle.
1782+
# instrument_aiohttp_server() patches the Application class via setattr, so it
1783+
# only affects instances created AFTER the call. Since root_app is already
1784+
# instantiated by build_root_app(), we must manually inject the middleware.
1785+
# A proper fix would restructure startup so that OTel instrumentation runs
1786+
# before Application creation (e.g., by moving OTel config to BootstrapConfig
1787+
# or by decoupling config loading from aiohttp cleanup contexts).
17831788
if root_ctx.config_provider.config.otel.enabled:
17841789
instrument_aiohttp_server()
17851790
instrument_aiohttp_client()

0 commit comments

Comments
 (0)