feat: add OpenTelemetry metrics for create jobs#802
Conversation
Signed-off-by: Eric W. Tramel <eric.tramel@gmail.com>
|
Fern preview: https://nvidia-preview-pr-802.docs.buildwithfern.com/nemo/datadesigner
|
Code Review: PR #802 — feat: add OpenTelemetry metrics for create jobsAuthor: eric-tramel · Base: SummaryThis PR adds default, pull-based OpenTelemetry/Prometheus metrics for The design correctly respects the package layering. OTel SDK/exporter ownership stays in The change is unusually well-tested: privacy (secret-sentinel scrubbing), lifecycle/rebind, concurrent creates, exact-once emission, init-failure cleanup, real HTTP scrape, and a subprocess test asserting the OTel SDK is not imported when disabled. Failure containment is a clear design goal and is consistently applied. FindingsCorrectness
Design / Architecture
Security / Privacy
Performance
Testing
Docs
Nits
Structural ImpactPre-computed by graphify; annotated with reviewer verification. Risk: HIGH (1 core abstraction(s) modified; 27 import direction violation(s))
Import Direction Violations (27)Legal direction: interface -> engine -> config
Core Abstractions Modified
High-Connectivity Changes
Cross-Package Dependencies
Reviewer note on the 27 import-direction violations: these are false positives from call-graph attribution. The flagged VerdictApprove (with minor, non-blocking nits). This is a high-quality, well-architected PR that respects the interface → engine → config layering, contains all telemetry failures so they cannot alter create results, and has strong privacy guarantees backed by explicit tests. The scheduler Suggested (optional) follow-ups: dedupe the 3× enable-check ternary in |
Greptile SummaryThis PR adds pull-based OpenTelemetry/Prometheus metrics for
|
| Filename | Overview |
|---|---|
| packages/data-designer/src/data_designer/integrations/opentelemetry.py | New file: process-owned OpenTelemetryRuntime singleton with per-run lifecycle management, event to metric translation, thread-safe gauge/counter state, and lazy OTel SDK initialization. _stop_server is correctly called outside self._lock to prevent a scrape-handler deadlock. |
| packages/data-designer-engine/src/data_designer/engine/dataset_builders/async_scheduler.py | Captures ambient RuntimeCorrelation at scheduler init time for run_id propagation; moves scheduler_job_completed emission to the finally block with outcome/error_type; replaces null-sink checks with scheduler_event_sink_accepts() interest filtering. |
| packages/data-designer-engine/src/data_designer/engine/models/clients/model_request_executor.py | Consolidates outcome tracking and model_request_completed emission into a single outer finally block; times only the actual model call (inner try/finally); eliminates duplicate per-branch emit_model_event calls. |
| packages/data-designer-config/src/data_designer/config/run_config.py | Adds otel_metrics_port: int |
| packages/data-designer-engine/src/data_designer/engine/observability.py | Adds scheduler_event_sink_accepts() and request_event_sink_accepts() helper functions with exception-safe interest filtering; adds @runtime_checkable to SchedulerAdmissionEventSink Protocol. |
| packages/data-designer/src/data_designer/interface/data_designer.py | Adds @_observe_create decorator to create() and wires _open_telemetry as request/scheduler event sink when otel_metrics_port is not None; reads run_config at call time, ensuring port and sink assignment are consistent. |
| packages/data-designer/tests/integrations/test_opentelemetry.py | 28-test integration suite covering metric values, attribute bounding, scrape content, active-request gauge balance, port rebind, unlock-before-stop regression, log scoping, overlapping teardown, and failure containment. |
Sequence Diagram
%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant Caller as Caller Thread
participant OTel as OpenTelemetryRuntime
participant Scheduler as AsyncTaskScheduler
participant Executor as ModelRequestExecutor
participant Prom as Prometheus HTTP
Caller->>OTel: observe_create(port) sets RuntimeCorrelation(run_id)
OTel->>OTel: _activate_run adds run_id to _active_run_ids
Caller->>Scheduler: create() via run_coroutine_threadsafe
Note over Scheduler: __init__ captures ambient run_id
Scheduler->>OTel: emit scheduler_job_started
loop per row-group
Scheduler->>OTel: emit row_group_checkpointed
Executor->>OTel: emit model_request_started (+1 gauge)
Executor->>OTel: emit model_request_completed (-1 gauge + histogram)
end
Prom-->>OTel: GET /metrics scrape
Scheduler->>OTel: emit scheduler_job_completed
Caller->>OTel: observe_create finally block cleanup
OTel->>OTel: _stop_server called OUTSIDE _lock
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant Caller as Caller Thread
participant OTel as OpenTelemetryRuntime
participant Scheduler as AsyncTaskScheduler
participant Executor as ModelRequestExecutor
participant Prom as Prometheus HTTP
Caller->>OTel: observe_create(port) sets RuntimeCorrelation(run_id)
OTel->>OTel: _activate_run adds run_id to _active_run_ids
Caller->>Scheduler: create() via run_coroutine_threadsafe
Note over Scheduler: __init__ captures ambient run_id
Scheduler->>OTel: emit scheduler_job_started
loop per row-group
Scheduler->>OTel: emit row_group_checkpointed
Executor->>OTel: emit model_request_started (+1 gauge)
Executor->>OTel: emit model_request_completed (-1 gauge + histogram)
end
Prom-->>OTel: GET /metrics scrape
Scheduler->>OTel: emit scheduler_job_completed
Caller->>OTel: observe_create finally block cleanup
OTel->>OTel: _stop_server called OUTSIDE _lock
Reviews (4): Last reviewed commit: "fix: address observability review feedba..." | Re-trigger Greptile
Expose lifecycle-aware dataset progress and paired active model request metrics. Add standard per-model GenAI attributes so external dashboards can track concurrent work without task-level OTel coupling. Signed-off-by: Eric W. Tramel <eric.tramel@gmail.com>
Signed-off-by: Eric W. Tramel <eric.tramel@gmail.com>
Signed-off-by: Eric W. Tramel <eric.tramel@gmail.com>
andreatgretel
left a comment
There was a problem hiding this comment.
One inline finding.
| raise self._provider_error_from_request_admission(exc) from exc | ||
| except asyncio.CancelledError: | ||
| raise | ||
| self._emit_model_event("model_request_started", item=item, lease=lease) |
There was a problem hiding this comment.
[P2] Keep started-event emission inside the lease cleanup scope
The admission lease is already acquired here, but this emission occurs before the try that guarantees its release. If KeyboardInterrupt occurs while the sink is running, the coroutine exits with the lease still active. I reproduced active_lease_count == 1 on this head, while the same forced path on main releases it with the local_cancelled outcome. Initialize the timing and outcome variables first, then emit inside the protected try. The synchronous attempt has the same regression.
nabinchha
left a comment
There was a problem hiding this comment.
Nice work on this one, @eric-tramel — this is a well-structured, privacy-conscious observability layer with impressively thorough tests.
Summary
Adds default, pull-based OpenTelemetry/Prometheus metrics for DataDesigner.create() on a loopback endpoint controlled by RunConfig.otel_metrics_port (default 9464, None to disable). The interface package owns the OTel SDK, meter provider, and HTTP listener; existing engine scheduler/request event seams feed the exporter, and a metric-only log handler tees severity counts. The implementation matches the PR description, keeps the config → engine → interface layering intact, defers heavy imports into _initialize(), and contains telemetry failures so they can't change create results.
Findings
Warnings — Worth addressing
packages/data-designer/src/data_designer/interface/data_designer.py:173 + run_config.py:194 — Telemetry is on by default, opening a listening socket on every create()
- What:
otel_metrics_portdefaults to9464, so everyDataDesigner.create()in every environment now binds a TCP listener (loopback) and keeps it open until process exit. This is a new, always-on side effect for existing users who never asked for metrics. - Why: In multi-instance hosts, CI, or notebook workflows this can surprise operators, and security scanners routinely flag open ports even on loopback. The graceful-degradation path (bind failure → warn → continue) is good, but the default posture is still "open a socket unless told not to."
- Suggestion: Worth a quick team confirmation that default-on is the intended contract vs. opt-in (e.g. default
None, enabled explicitly). If default-on is deliberate, consider calling it out prominently in the release notes/changelog so operators aren't caught off guard. Not blocking if the team already signed off on this.
packages/data-designer-engine/src/data_designer/engine/models/clients/model_request_executor.py:125,176 — Confirming the existing P2 (started-event emitted before the release-guarding try)
- What: I'm not re-raising new feedback here, just corroborating @andreatgretel's inline comment:
_emit_model_event("model_request_started", ...)runs after the lease is acquired but before thetrythat guarantees release._emit_model_eventswallowsExceptionbut notBaseException, so aKeyboardInterruptduring the started emit leaks the lease. This still reproduces on the current head. - Why: It's a genuine (if narrow) resource-leak window, and the fix is cheap.
- Suggestion: Move the
startedemission inside the protectedtry(initializestarted_at/duration_seconds/outcomefirst, then emit), as suggested in the inline thread. Same for both the sync and async attempt paths.
packages/data-designer-engine/src/data_designer/engine/models/clients/model_request_executor.py:272 — Request correlation relies on the contextvar being present on the calling thread
- What:
_item()readsruntime_correlation_provider.current(), andemit_request_eventdrops any event whosecaptured_correlationhas norun_id. The active-request gauge andgen_ai.client.operation.durationtherefore only populate when the model call executes in a context that inherited the contextvar set byobserve_create. - Why: This is fine for the async path (tasks inherit the context), but for any sync/thread-pool execution mode that runs client calls on worker threads that didn't copy the context,
current()returnsNoneand those requests silently won't appear in the model-activity metrics. Want to make sure that's understood/acceptable. - Suggestion: Could we confirm the concurrency modes that route through
ModelRequestExecutorall preserve the contextvar (or add a targeted test for the sync/threaded path)? If sync-mode gaps are expected, a one-line note in the docs/metric description would set expectations.
packages/data-designer/src/data_designer/integrations/opentelemetry.py — OpenTelemetryRuntime is carrying four responsibilities (SRP)
- What: One ~500-line class owns (a) HTTP server + meter-provider lifecycle, (b) instrument definitions, (c) a domain state machine (active runs, dataset-progress math, in-flight request accounting), and (d) event adaptation for three sinks. The progress aggregation (
_start_dataset_progress/_advance_dataset_progress/_finish_active_dataset/_active_dataset_progress, ~404-435) is a self-contained, OTel-agnostic state machine. - Why: The progress semantics can only be tested by standing up a Prometheus server, and every concern shares the same
_lock. This will get harder to reason about as instruments are added. - Suggestion: Pull the progress math into a small
DatasetProgressTracker(no OTel deps, directly unit-testable) and consider a frozen_MetricInstrumentscontainer for the instruments; leaveOpenTelemetryRuntimeas orchestration + lifecycle. Fine as a follow-up if it's too much for this PR. (Naming:DatasetProgressTrackerstays un-prefixed since the whole point is direct testability — STYLEGUIDE prefers public over private for testable helpers — whereas_MetricInstrumentsis a dumb container tested through the runtime, so the underscore fits.)
packages/data-designer/src/data_designer/integrations/opentelemetry.py:84-96 — ~11 attributes typed Any sidestep the "typed code" invariant
- What:
_registry,_meter_provider,_server,_create_duration,_dataset_records, … are allAnybecause the OTel types aren't imported at module scope. - Why: AGENTS.md/STYLEGUIDE call out avoiding overly broad
Any; as-is the checker can't catch e.g. calling.add()on a histogram vs.record()on a counter. - Suggestion: Import the OTel/prometheus types under
TYPE_CHECKING(the same pattern used for lazy heavy libs) and annotate precisely (Histogram,Counter,UpDownCounter,ObservableGauge,MeterProvider,CollectorRegistry,HTTPServer). This is a low-risk, high-clarity win and pairs naturally with the split above.
model_request_executor.py:287 + data_designer.py:745 — Hot-path events are built before the gate, and preview() pays for events it always drops
- What:
_emit_model_eventunconditionally builds the fullRequestAdmissionEvent— includingself._request_admission.pressure.snapshot(...)and the recursive_json_safenormalization in__post_init__— whenever_event_sink is not None, then dispatches toemit_request_event, which drops it if the run isn't active. Unlike the scheduler path there's noaccepts_request_eventfast-path filter. Because_create_resource_providerwires the sink for bothcreateandpreview(onlycreateactivates a run), every model call on thepreviewpath does this build-then-drop. - Why: Model requests are the highest-volume events, and
previewis latency-sensitive; the per-call snapshot + JSON normalization is wasted work there. - Suggestion: Add an
accepts_request_event(event_kind)gate mirroringscheduler_event_sink_acceptsand check it before building the event / taking the pressure snapshot. That both restores symmetry with the scheduler path and makes the inactive-run/preview case exit cheaply (cleaner than special-casing preview at the wiring site).
Engine observability now has three inconsistent emission seams (strategic design debt) — observability.py, request_admission/controller.py:770-777, async_scheduler.py, model_request_executor.py
- What: The DIP itself is clean (engine defines the sink
Protocols; the interface'sOpenTelemetryRuntimeimplements them; correlation flows the other way via theruntime_correlation_providercontextvar). But the emission side now has three different styles side by side:AsyncScheduler→ single direct sink with anaccepts_scheduler_eventinterest filter.RequestAdmissionController._emit_events→ direct sink and the globalemit_request_admission_eventcallback registry (the latter is howprogress/reporter.pyconsumes events), no filter.ModelRequestExecutor→ single direct sink only (somodel_request_started/completedreach OTel but not the progress reporter), no filter.
- Why: There's no single answer to "how do I observe request activity?" The controller's dual fan-out also has mismatched reliability — the direct-sink call is
try/except-guarded but theemit_request_admission_event(event)call on line 777 is not. As more consumers appear, this divergence compounds. - Suggestion: Converge on one seam over time — e.g. make the progress reporter just another registered subscriber/sink, and give both scheduler and request paths the same optional
accepts_*filter, so the model is uniformly "producer emits event → fan-out to N sinks." Bigger than this PR should take on, but worth capturing as the design debt this feature adds.
packages/data-designer-engine/src/data_designer/engine/observability.py:227 — accepts_scheduler_event is a phantom (undeclared) protocol method
- What:
scheduler_event_sink_acceptsprobesgetattr(sink, "accepts_scheduler_event", None), but that method isn't on theSchedulerAdmissionEventSinkProtocol (which only declaresemit_scheduler_event). - Why: This is a latent bug, not just a style nit — a rename/typo of the method silently degrades to "accept everything" (the filter becomes a no-op), and neither the type checker nor the contract would catch it. Given the filter exists partly for hot-path cost, a silent no-op has real consequences.
- Suggestion: Declare
accepts_scheduler_eventon the Protocol (or aFilteringSchedulerAdmissionEventSinksub-Protocol checked viaisinstance) so the filter is part of the contract instead of duck-typed.
packages/data-designer/src/data_designer/integrations/opentelemetry.py:66-70 — Swallowed exceptions make telemetry bugs undiagnosable (error handling)
- What: The "never break create" policy is applied via bare swallows — e.g.
_MetricLogHandler.emitdoesexcept Exception: passwith no logging at all — so a genuine bug inside the instrumentation is completely invisible in the field. - Why: STYLEGUIDE flags swallowed exceptions as an error-handling problem. The intent (don't break create) is right, but "silently drop with zero trace" means a broken metric would never be noticed or reproducible.
- Suggestion: Keep the swallow, but log at
debugwithexc_info=Trueinstead of barepass, and optionally gate a strict re-raise behind an env var (e.g.DATA_DESIGNER_OTEL_STRICT=1) for tests/field debugging.
packages/data-designer-config/src/data_designer/config/run_config.py:194 — otel_metrics_port=None reads like a kill switch but isn't
- What:
Nonemeans "don't activate for this invocation," yet a listener started by a prior run keeps serving. The field overloads "enabled" and "which port." - Why: This is a user-facing footgun with a security angle — someone who sets
Nonespecifically to stop metrics being served will still have the prior run's endpoint open. Combined with the default-on Warning above, the mismatch between expectation and behavior could bite. - Suggestion: At minimum, clarify in the docstring that
Nonedisables activation for the invocation only (not a process-wide stop), and document how to actually stop the listener. Splitting intoenabled: bool+port: intwould remove the overload but is probably more than needed.
Suggestions — Take it or leave it
Four optional polish items (click to expand)
packages/data-designer-engine/src/data_designer/engine/dataset_builders/dataset_builder.py:976 — Defensive getattr on a field that always exists
- What:
scheduler_event_sink=getattr(self._resource_provider, "scheduler_event_sink", None). Now thatResourceProviderdeclaresscheduler_event_sink: SchedulerAdmissionEventSink | None = None, the attribute always exists. - Why: The
getattrfallback reads as "this might not be there," which is misleading for a declared Pydantic field. - Suggestion: Simplify to
self._resource_provider.scheduler_event_sinkunless there's a compat reason (e.g. externally-constructed providers) — in which case a short comment would help.
packages/data-designer/src/data_designer/interface/data_designer.py:743-757 — The "is telemetry on?" rule is duplicated four times (DRY)
- What:
self._open_telemetry if self._run_config.otel_metrics_port is not None else Noneappears at three call sites (request sink, scheduler sink, request-admission controller), plus the port passed intoobserve_create. - Why: The enablement invariant is smeared across the interface; changing it means touching several spots.
- Suggestion: Extract a
self._metrics_sink()accessor returning the runtime orNone, and use it at each site.
packages/data-designer/src/data_designer/integrations/opentelemetry.py:491-492 — Global singleton + atexit registered as an import side effect
- What: Importing the module constructs
_RUNTIMEand registersatexit.register(_RUNTIME.shutdown). - Why: A process-global lifecycle established just by importing the interface is a classic testability smell (the tests already work around it with a fresh-instance fixture). It's cheap today (no OTel imports fire at construction), so low urgency.
- Suggestion: Optionally make
get_open_telemetry_runtime()construct lazily on first call and registeratexitthere once.
packages/data-designer/src/data_designer/integrations/opentelemetry.py:335-345 — Progress gauge blends independent jobs into one process-wide float
- What:
_dataset_progress_valueis a single number aggregated across all active runs, with the last finished value lingering until the next start. - Why: For concurrent creates, one gauge that shifts between "this job / blended / stale residual" is semantically muddy on a dashboard. Fine for the common single-job case.
- Suggestion: If overlapping creates become normal, prefer a per-run gauge label so each job reports its own fraction. Defer to a follow-up unless multi-job dashboards are an immediate need (it's a metric-schema change).
What Looks Good
- Failure containment is excellent —
_activate_run,_initialize, the log handler,_record_create_duration, and_finish_active_requestsall defensively suppress/rollback so telemetry can never break a create. The partial-init cleanup in_initialize(removing the handler and shutting down the provider on failure) is especially careful. - The P1 deadlock fix is done right —
_rebindnow returns the old(server, thread)and_stop_serverruns outsideself._lockin both_activate_runandshutdown, withtest_runtime_stops_rebound_listener_outside_runtime_locklocking in the behavior. TheRLockchoice for the re-entrant progress helpers is appropriate. - Privacy posture is thorough —
_bounded_attributestrips/bounds attribute values, and the metric-only log handler tees severity counts without ever exporting log bodies. The docs section spells out the loopback-only, no-auth, metrics-only contract clearly. - Test suite is genuinely comprehensive — post-teardown event rejection, orphan/duplicate request reconciliation, idle-listener rebind, conflicting-port reuse, concurrent creates sharing one exporter, and
test_disabled_runtime_does_not_import_otel_sdk_in_fresh_processguarding the lazy-import contract. These verify behavior, not plumbing.
Suggested Follow-up Issues
For the larger design items we're intentionally not folding into this PR, let's open tracking issues so they don't get lost (happy to file these — just confirm):
- Unify the three engine observability emission seams — converge direct-sink / global-registry / sink-with-filter into one "producer → fan-out to N sinks" model, including guarding the unguarded
emit_request_admission_eventcall and giving both paths anaccepts_*filter. (Strategic; highest-value.) - Split
OpenTelemetryRuntime— extractDatasetProgressTracker(directly unit-testable) and a typed_MetricInstrumentscontainer; leave the runtime as orchestration + lifecycle. - Lazy-construct the runtime singleton — move construction +
atexitregistration intoget_open_telemetry_runtime()to drop the import side effect. - Per-run progress gauge label — only if overlapping creates become a supported scenario (metric-schema change).
The Warnings above are small enough to fix in this PR rather than defer (the accepts_scheduler_event Protocol declaration, the swallowed-exception logging, and the otel_metrics_port=None docstring), as are the DRY _metrics_sink() accessor and the getattr cleanup.
Verdict
Needs changes — nothing here is a hard blocker on the happy path, but before merge it's worth: (1) getting explicit sign-off on default-on telemetry (or flipping to opt-in), and (2) closing the still-open P2 lease-leak window in model_request_executor. The correlation-propagation question is a "confirm or add a test" item.
On the design side, the low-risk Warnings worth folding into this PR are the hot-path/preview build-then-drop (accepts_request_event gate), the Any typing (TYPE_CHECKING), the phantom-protocol method (declare accepts_scheduler_event), the swallowed-exception logging, and the otel_metrics_port=None docstring — plus the small _metrics_sink()/getattr cleanups. The god-object split, lazy singleton, per-run progress label, and especially the three inconsistent emission seams are the larger items better tracked as follow-up issues than jammed into this PR.
ruff check and ruff format --check pass clean on all changed source files.
This review was generated by an AI assistant.
andreatgretel
left a comment
There was a problem hiding this comment.
One inline question.
…ervability Signed-off-by: Eric W. Tramel <eric.tramel@gmail.com> # Conflicts: # packages/data-designer/src/data_designer/interface/data_designer.py
- release request leases when started-event emission is interrupted - skip request events that the configured sink does not consume - preserve scheduler terminal diagnostics and classify early shutdown - bound exported model labels and strengthen correlation coverage Signed-off-by: Eric W. Tramel <eric.tramel@gmail.com>
|
Implemented the requested review follow-ups in What changed:
Validation:
The PR is conflict-free and mergeable. Please re-review/clear the prior changes-requested state when convenient. |
📋 Summary
What. Adds default, pull-based OpenTelemetry metrics for
DataDesigner.create()on a loopback Prometheus endpoint controlled byRunConfig.Why. Gives operators current create progress, throughput, scheduler outcomes, model activity, request completion/latency, errors, and safe log-volume signals without making task code depend on OpenTelemetry or adding parallel instrumentation paths.
The interface layer owns a private OTel meter provider, registry, and HTTP listener. Existing generic engine scheduler and request-event seams feed the exporter, while a metric-only logging handler tees severity counts without exporting log bodies. Telemetry failures are contained and cannot change create results.
🔗 Related Issue
None.
🔄 Changes
RunConfig.otel_metrics_port, defaulting to loopback port9464;Nonedisables telemetry for an invocation./metrics:data_designer.create.durationdata_designer.dataset.recordsdata_designer.dataset.progressdata_designer.scheduler.eventsdata_designer.model.request.activegen_ai.client.operation.durationdata_designer.log.recordsgen_ai.operation.name,gen_ai.provider.name, andgen_ai.request.modelattributes.📖 Usage
The default create path starts
http://127.0.0.1:9464/metrics:Choose another loopback port or disable telemetry:
Prometheus can scrape
127.0.0.1:9464at/metrics. The listener is process-wide and remains available after a create job so final cumulative metrics can be collected. Generated-record totals and progress advance at durable row-group checkpoints; the active-request gauge and request-duration count provide live activity between checkpoints.📊 External dashboard validation
A local external Prometheus/Grafana stack scraped the listener every 2 seconds and rendered current listener health, active jobs, durable progress, generated records, active requests by exact model, attempts/second, p95 latency, scheduler totals, failures, and log volume.
The end-to-end demonstration generated 512 records through 1,536 logical model tasks using the
nvidia-internalprovider and three non-8B models, each configured withmax_tokens=1024:nvidia/openai/gpt-oss-20bnvidia/nvidia/nemotron-nano-31b-v3nvidia/openai/gpt-oss-120bAll 1,536 logical tasks completed successfully. The external collector observed two transient
internal_serverattempts on the 120B model, two matchingtask.retry_deferredscheduler events, and final job success. Dashboard queries use raw counters for event/failure totals, short rate windows aligned with the 2-second scrape interval, a lifecycle-aware progress gauge, and model-separated GenAI series so the panels represent current state instead of long-window residual activity.The original POC capture is retained below; the validated dashboard now includes the live-state and 2-second refresh refinements described above.
📝 Changelog
RunConfigport/disable option.🧪 Testing
make check-all— passedmake test— 3,907 passed, 1 existing skipFocused scheduler, request-admission, custom-bridge, and OpenTelemetry review-fix suite — 302 passed
Seven-persona delegated code review — no actionable findings remain after targeted follow-up
Deterministic delayed-event, overlapping-teardown, and unlocked-rebind regressions — passed
Isolated package-install suites — passed during feature validation
Import-performance and lazy-import checks — passed
Fern validation — 0 errors, 1 existing warning
Live
nvidia-internalmulti-model run — 512 records and 1,536 logical tasks completed successfully while an external Prometheus/Grafana stack observed executionmake testpassesUnit tests added/updated
E2E behavior validated
👀 Review areas
✅ Checklist
Description updated with AI