Browse Source

fix(comment): include context in notify failure logs

Pass postId and commentId into reply notification flow and log structured failure context with receiverUserId and reason while keeping best-effort behavior unchanged.

Made-with: Cursor
main
npmrun 3 weeks ago
parent
commit
5bd43eb835
  1. 2
      server/api/public/profile/[publicSlug]/posts/[postSlug]/comments.post.ts
  2. 2
      server/api/public/unlisted/[publicSlug]/[shareToken]/comments.post.ts
  3. 19
      server/service/comment-notify/index.test.ts
  4. 22
      server/service/comment-notify/index.ts

2
server/api/public/profile/[publicSlug]/posts/[postSlug]/comments.post.ts

@ -47,6 +47,8 @@ export default defineEventHandler(async (event) => {
});
void notifyReplyCommentCreated({
postId: ctx.id,
commentId: newCommentId,
parentId: parsed.parentId,
actorUserId: viewer?.id ?? null,
replyBody: parsed.body,

2
server/api/public/unlisted/[publicSlug]/[shareToken]/comments.post.ts

@ -47,6 +47,8 @@ export default defineEventHandler(async (event) => {
});
void notifyReplyCommentCreated({
postId: ctx.id,
commentId: newCommentId,
parentId: parsed.parentId,
actorUserId: viewer?.id ?? null,
replyBody: parsed.body,

19
server/service/comment-notify/index.test.ts

@ -45,7 +45,7 @@ describe("notifyReplyCommentCreated", () => {
smtpPass: "smtp-pass",
});
await notifyReplyCommentCreated({ parentId: 100, actorUserId: 1, replyBody: "hello" }, deps);
await notifyReplyCommentCreated({ postId: 10, commentId: 200, parentId: 100, actorUserId: 1, replyBody: "hello" }, deps);
expect(state.sendMailCalled).toBe(false);
});
@ -54,7 +54,7 @@ describe("notifyReplyCommentCreated", () => {
const { deps, state } = createDeps();
deps.getReceiverNotifyEnabled = async () => false;
await notifyReplyCommentCreated({ parentId: 100, actorUserId: 1, replyBody: "hello" }, deps);
await notifyReplyCommentCreated({ postId: 10, commentId: 201, parentId: 100, actorUserId: 1, replyBody: "hello" }, deps);
expect(state.sendMailCalled).toBe(false);
});
@ -62,7 +62,7 @@ describe("notifyReplyCommentCreated", () => {
test("无 parentId -> 不发送", async () => {
const { deps, state } = createDeps();
await notifyReplyCommentCreated({ parentId: null, actorUserId: 1, replyBody: "hello" }, deps);
await notifyReplyCommentCreated({ postId: 10, commentId: 202, parentId: null, actorUserId: 1, replyBody: "hello" }, deps);
expect(state.sendMailCalled).toBe(false);
});
@ -71,8 +71,19 @@ describe("notifyReplyCommentCreated", () => {
const { deps, state } = createDeps();
deps.getParentAuthorUserId = async () => 1;
await notifyReplyCommentCreated({ parentId: 100, actorUserId: 1, replyBody: "hello" }, deps);
await notifyReplyCommentCreated({ postId: 10, commentId: 203, parentId: 100, actorUserId: 1, replyBody: "hello" }, deps);
expect(state.sendMailCalled).toBe(false);
});
test("发送异常 -> 不抛出(best-effort)", async () => {
const { deps } = createDeps();
deps.sendMail = async () => {
throw new Error("smtp send failed");
};
await expect(
notifyReplyCommentCreated({ postId: 10, commentId: 204, parentId: 100, actorUserId: 1, replyBody: "hello" }, deps),
).resolves.toBeUndefined();
});
});

22
server/service/comment-notify/index.ts

@ -31,6 +31,16 @@ function hasValue(value: string): boolean {
return value.trim().length > 0;
}
function getReason(error: unknown): string {
if (error instanceof Error && hasValue(error.message)) {
return error.message;
}
if (typeof error === "string" && hasValue(error)) {
return error;
}
return "unknown";
}
function isSmtpConfigReady(config: NotifyGlobalConfig): boolean {
return (
config.enabled &&
@ -138,18 +148,21 @@ function getDefaultDeps(): NotifyDeps {
export async function notifyReplyCommentCreated(
input: {
postId: number;
commentId: number;
parentId: number | null;
actorUserId: number | null;
replyBody: string;
},
deps: NotifyDeps = getDefaultDeps(),
): Promise<void> {
let receiverUserId: number | null = null;
try {
if (input.parentId == null) {
return;
}
const receiverUserId = await deps.getParentAuthorUserId(input.parentId);
receiverUserId = await deps.getParentAuthorUserId(input.parentId);
if (receiverUserId == null) {
return;
}
@ -179,6 +192,11 @@ export async function notifyReplyCommentCreated(
replyBody: input.replyBody,
});
} catch (error) {
logger.warn("failed to send reply comment notify email", error);
logger.warn("failed to send reply comment notify email", {
postId: input.postId,
commentId: input.commentId,
receiverUserId,
reason: getReason(error),
});
}
}

Loading…
Cancel
Save