Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(hook): 支持配置多个Hook #1230

Merged
merged 1 commit into from
Apr 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/violet-deers-sniff.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@scow/config": patch
"@scow/lib-hook": patch
"@scow/docs": patch
---

支持填写多个 hook 地址
12 changes: 12 additions & 0 deletions docs/docs/integration/scow-api-hook/hook.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,19 @@ title: SCOW Hook

```yaml title="config/common.yaml"
scowHook:
# 启用SCOW Hook功能,默认为true
# enabled: true

# 若您只有一个hook,您可以直接使用url属性,并填入您的Hook的地址
url: 您的gRPC服务器的地址

# 若您有多个hook,则可以使用hooks属性,逐个填入您的地址。
# 若您填写了hooks,则url属性将会被忽略
hooks:
- name: hook-name-1 # hook名,可选,若填写了,则在日志中可以看到被调用的hook的名字
url: hook 1地址 # hook服务器端地址
- name: hook-name-2
url: hook 2地址
```

5. 重启SCOW
Expand Down
6 changes: 5 additions & 1 deletion libs/config/src/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@ export const ScowApiConfigSchema = Type.Object({

export const ScowHookConfigSchema = Type.Object({
enabled: Type.Boolean({ description: "是否启用SCOW Hook", default: true }),
url: Type.String({ description: "SCOW Hook的URL" }),
url: Type.Optional(Type.String({ description: "SCOW Hook的URL" })),
hooks: Type.Optional(Type.Array(Type.Object({
name: Type.Optional(Type.String({ description: "Hook的名称" })),
url: Type.String({ description: "Hook的URL" }),
}), { description: "多个Hook的URL。SCOW将会以数组的顺序逐个调用各个hook。" })),
}, { description: "SCOW Hook配置" });

export const CommonConfigSchema = Type.Object({
Expand Down
55 changes: 38 additions & 17 deletions libs/hook/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,33 @@ export const createHookClient = (
config: ScowHookConfigSchema | undefined,
logger: Logger,
) => {
const client = (config && config.enabled)
? new HookServiceClient(config.url, ChannelCredentials.createInsecure())
: undefined;

if (config && client) {
logger.info("Hook configured to %s", config.url);
const hooks: {
name?: string;
client: HookServiceClient,
}[] = [];

const createHook = (url: string, name?: string) => {
return {
name: name ?? url,
client: new HookServiceClient(url, ChannelCredentials.createInsecure()),
};
};

if (!config) {
logger.info("Hook is not configured.");
} else if (!config.enabled) {
logger.info("Hook is explicitly disabled in config.");
} else if (config.hooks) {
for (const hook of config.hooks) {
hooks.push(createHook(hook.url, hook.name));
}
logger.info("Hooks are configured with %d hooks", hooks.length);
} else if (config.url) {
hooks.push(createHook(config.url));
logger.info("Hook %s is configured.", config.url);
} else {
logger.info("Hook disabled");
logger.info("No hooks or url is provided in hook config. Hook is not configured.");
}

return {
Expand All @@ -39,22 +58,24 @@ export const createHookClient = (
eventPayload: (Event & { $case: TEventName })[TEventName],
logger: Logger,
) => {

if (!client) {
if (hooks.length === 0) {
logger.debug("Attempt to call hook %s with %o", eventName, eventPayload);
return;
}

logger.info("Calling hook %s with %o", eventName, eventPayload);
logger.info("Calling hooks concurrently with event name %s and payload %o", eventName, eventPayload);

return await asyncUnaryCall(client, "onEvent", {
metadata: { time: new Date().toISOString() },
// @ts-ignore
event: { $case: eventName, [eventName]: eventPayload },
}).then(
() => { logger.debug("Hook call completed"); },
(e) => { logger.error(e, "Error when calling hook"); },
);
await Promise.all(hooks.map(async (hook) => {
logger.info("Calling hook %s", hook.name);
await asyncUnaryCall(hook.client, "onEvent", {
metadata: { time: new Date().toISOString() },
// @ts-ignore
event: { $case: eventName, [eventName]: eventPayload },
}).then(
() => { logger.debug("Hook call completed"); },
(e) => { logger.error(e, "Error when calling hook"); },
);
}));
},
};
};
Expand Down
Loading