feat: expose executor job observability

This commit is contained in:
john
2026-07-24 23:31:29 +08:00
parent bbb43f97a3
commit 396bb78200
18 changed files with 733 additions and 68 deletions
+25
View File
@@ -410,6 +410,8 @@ export type OrchestratorCanaryReadiness = {
latencyMs: number | null;
checkpointKind: string | null;
checkpointDurable: boolean | null;
executorJobStoreKind: string | null;
executorJobStoreDurable: boolean | null;
execution: string | null;
};
checks: OrchestratorCanaryReadinessCheck[];
@@ -452,6 +454,29 @@ export type OrchestratorShadowRunDetail = {
data?: Record<string, unknown> | null;
}>;
error: { code: string; message: string } | null;
executorJob: {
available: boolean;
state: {
version?: string;
jobId?: string;
executor?: string;
status?: string;
reason?: string;
attempts?: number;
createdAt?: number;
updatedAt?: number;
} | null;
events: Array<{
version?: string;
eventId?: string;
jobId?: string;
sequence?: number;
type?: string;
timestamp?: number;
data?: Record<string, unknown> | null;
}>;
error: { code: string; message: string } | null;
};
};
};
+1 -1
View File
@@ -173,7 +173,7 @@ export function OrchestratorPage() {
<div>
<h3 style={{ margin: 0 }}>Executor Gateway</h3>
<p style={{ margin: '4px 0 0', color: '#68716c', fontSize: 13 }}>
Phase 3.3 blocked contract-only
Phase 3.4 contract-only
</p>
</div>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(220px, 1fr))', gap: 10 }}>
@@ -29,6 +29,7 @@ const readinessCheckLabels: Record<string, string> = {
shadow_mode: '当前保持 Shadow',
service_healthy: '服务健康',
durable_checkpoint: '持久化 checkpoint',
durable_executor_job_store: '持久化 Executor Job Store',
observe_only: '仅观察不执行',
sample_volume: '有效样本量',
shadow_success_rate: 'Shadow 成功率',
@@ -301,6 +302,13 @@ export function OrchestratorShadowPanel() {
{selected.remote.error.code}: {selected.remote.error.message}
</p>
) : null}
{selected.remote.executorJob.error ? (
<p className="alert">
Executor Job{selected.remote.executorJob.error.code}
{' '}
{selected.remote.executorJob.error.message}
</p>
) : null}
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(300px, 1fr))', gap: 12 }}>
<div>
<strong>LangGraph checkpoint</strong>
@@ -315,6 +323,31 @@ export function OrchestratorShadowPanel() {
</pre>
</div>
</div>
{selected.remote.executorJob.available ? (
<div
style={{
borderTop: '1px solid #edf1ef',
marginTop: 12,
paddingTop: 12,
display: 'grid',
gridTemplateColumns: 'repeat(auto-fit, minmax(300px, 1fr))',
gap: 12,
}}
>
<div>
<strong>Executor Job </strong>
<pre style={{ whiteSpace: 'pre-wrap', overflowWrap: 'anywhere', fontSize: 12 }}>
{JSON.stringify(selected.remote.executorJob.state, null, 2)}
</pre>
</div>
<div>
<strong>Executor Job </strong>
<pre style={{ whiteSpace: 'pre-wrap', overflowWrap: 'anywhere', fontSize: 12 }}>
{JSON.stringify(selected.remote.executorJob.events, null, 2)}
</pre>
</div>
</div>
) : null}
</div>
) : null}
</div>