feat: initialize parent-bff service with full core features

add complete parent-bff implementation including:
- GraphQL endpoint with depth/cost validation
- ChildGuard越权校验 with redis cache and singleflight
- parallel orchestration with partial failure fallback
- three-level cache fallback strategy (Redis + LRU + downstream)
- Kafka consumer for cache invalidation and notification push
- opossum circuit breaker for downstream services
- Prometheus metrics and SLO alerts
- Helm chart for k8s deployment with multi-environment configs
- Grafana dashboard for observability
- complete unit and integration tests
This commit is contained in:
SpecialX
2026-07-10 18:49:06 +08:00
parent a7d8f92227
commit 2229309a1e
88 changed files with 11221 additions and 0 deletions

View File

@@ -0,0 +1,120 @@
import { describe, it, expect } from "vitest";
import { orchestrate } from "../../src/aggregation/orchestrator.js";
describe("Orchestrator", () => {
describe("全部成功", () => {
it("返回所有结果且 partial=false", async () => {
const result = await orchestrate({
a: Promise.resolve("value-a"),
b: Promise.resolve(42),
c: Promise.resolve({ key: "val" }),
});
expect(result.partial).toBe(false);
expect(result.failures).toHaveLength(0);
expect(result.results.a).toBe("value-a");
expect(result.results.b).toBe(42);
expect(result.results.c).toEqual({ key: "val" });
});
});
describe("部分失败降级(测试用例 5", () => {
it("data-ana 失败时该字段为 null其他字段正常", async () => {
const result = await orchestrate({
parent: Promise.resolve({ id: "parent-001", name: "王家长" }),
children: Promise.resolve([
{ id: "student-001", name: "李同学" },
]),
analytics: Promise.reject(new Error("data-ana connection refused")),
});
expect(result.partial).toBe(true);
expect(result.results.parent).toEqual({ id: "parent-001", name: "王家长" });
expect(result.results.children).toEqual([
{ id: "student-001", name: "李同学" },
]);
expect(result.results.analytics).toBeNull();
expect(result.failures).toHaveLength(1);
expect(result.failures[0]!.key).toBe("analytics");
});
it("多个失败都记录在 failures 中", async () => {
const result = await orchestrate({
ok: Promise.resolve("ok"),
fail1: Promise.reject(new Error("err1")),
fail2: Promise.reject(new Error("err2")),
});
expect(result.partial).toBe(true);
expect(result.failures).toHaveLength(2);
expect(result.failures.map((f) => f.key)).toContain("fail1");
expect(result.failures.map((f) => f.key)).toContain("fail2");
expect(result.results.ok).toBe("ok");
expect(result.results.fail1).toBeNull();
expect(result.results.fail2).toBeNull();
});
});
describe("全部失败", () => {
it("所有字段为 null 且 partial=true", async () => {
const result = await orchestrate({
a: Promise.reject(new Error("err-a")),
b: Promise.reject(new Error("err-b")),
});
expect(result.partial).toBe(true);
expect(result.results.a).toBeNull();
expect(result.results.b).toBeNull();
expect(result.failures).toHaveLength(2);
});
});
describe("空任务", () => {
it("返回空结果且 partial=false", async () => {
const result = await orchestrate({});
expect(result.partial).toBe(false);
expect(result.failures).toHaveLength(0);
expect(Object.keys(result.results)).toHaveLength(0);
});
});
describe("并行执行", () => {
it("任务并行执行而非串行", async () => {
const delay = (ms: number) => new Promise((r) => setTimeout(r, ms));
const start = Date.now();
await orchestrate({
a: delay(100).then(() => "a"),
b: delay(100).then(() => "b"),
c: delay(100).then(() => "c"),
});
const elapsed = Date.now() - start;
// 并行:总耗时约 100ms而非 300ms
expect(elapsed).toBeLessThan(250);
});
});
describe("failures 结构", () => {
it("failure 包含 key 和 error", async () => {
const error = new Error("test error");
const result = await orchestrate({
failing: Promise.reject(error),
});
expect(result.failures).toHaveLength(1);
expect(result.failures[0]!.key).toBe("failing");
expect(result.failures[0]!.error).toBe(error);
});
it("非 Error 类型的 rejection 也记录", async () => {
const result = await orchestrate({
failing: Promise.reject("string error"),
});
expect(result.failures).toHaveLength(1);
expect(result.failures[0]!.error).toBe("string error");
});
});
});