Skip to content
Open
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
14 changes: 8 additions & 6 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,14 +165,16 @@ async function recordSince(env: Env, date: string): Promise<void> {

// Fire-and-forget counter increments. Bundled onto ctx.waitUntil so they never
// add latency to the user-facing response.
function bumpMetrics(env: Env, ctx: ExecutionContext, deltas: MetricCounts): void {
function bumpMetrics(env: Env, ctx: ExecutionContext | undefined, deltas: MetricCounts): void {
if (Object.keys(deltas).length === 0) return;
const date = todayUtc();
ctx.waitUntil(Promise.all([
const writeMetrics = Promise.all([
addCounts(env, METRIC_ALL_KEY, deltas),
addCounts(env, metricDayKey(date), deltas, METRIC_TTL_SECONDS),
recordSince(env, date),
]).then(() => undefined));
]).then(() => undefined);
if (ctx?.waitUntil) ctx.waitUntil(writeMetrics);
else void writeMetrics;
Comment on lines +171 to +177

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The writeMetrics promise is executed in a "fire-and-forget" manner. If any of the underlying KV operations fail or if the RATE_KV binding is misconfigured/undefined, the promise will reject. Without a .catch() handler, this rejection will bubble up as an unhandled promise rejection, which can cause issues in the runtime or fail test suites.

Adding a .catch() block ensures that metric-writing failures are safely logged and do not disrupt the main request lifecycle or test execution.

Suggested change
const writeMetrics = Promise.all([
addCounts(env, METRIC_ALL_KEY, deltas),
addCounts(env, metricDayKey(date), deltas, METRIC_TTL_SECONDS),
recordSince(env, date),
]).then(() => undefined));
]).then(() => undefined);
if (ctx?.waitUntil) ctx.waitUntil(writeMetrics);
else void writeMetrics;
const writeMetrics = Promise.all([
addCounts(env, METRIC_ALL_KEY, deltas),
addCounts(env, metricDayKey(date), deltas, METRIC_TTL_SECONDS),
recordSince(env, date),
]).then(() => undefined)
.catch(err => {
console.error('Failed to write metrics:', err);
});
if (ctx?.waitUntil) ctx.waitUntil(writeMetrics);
else void writeMetrics;

}

function recentDates(days: number): string[] {
Expand Down Expand Up @@ -489,7 +491,7 @@ export function newId(): string {
return btoa(String.fromCharCode(...bytes)).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
}

export async function handleAnalyze(req: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
export async function handleAnalyze(req: Request, env: Env, ctx?: ExecutionContext): Promise<Response> {
if (req.method === 'GET') {
return Response.json({
description: 'PromptScope analyze API',
Expand Down Expand Up @@ -611,7 +613,7 @@ export async function handleAnalyze(req: Request, env: Env, ctx: ExecutionContex
});
}

export async function handleLicense(req: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
export async function handleLicense(req: Request, env: Env, ctx?: ExecutionContext): Promise<Response> {
if (req.method === 'GET') {
return Response.json({
auth_header: 'x-promptscope-license',
Expand All @@ -637,7 +639,7 @@ export async function handleLicense(req: Request, env: Env, ctx: ExecutionContex
}, { status });
}

export async function handleShare(req: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
export async function handleShare(req: Request, env: Env, ctx?: ExecutionContext): Promise<Response> {
if (req.method === 'POST') {
let body: any;
try { body = await req.json(); } catch { return Response.json({ error: 'invalid JSON' }, { status: 400 }); }
Expand Down
Loading
Loading