Skip to content

Bug: Campaign stats uses Promise.all — one failing query causes total endpoint failure #371

@gboigwe

Description

@gboigwe

Description

In backend/src/db/repositories/campaigns.ts, the getStats() function uses Promise.all() with three Prisma queries, but has no error handling for partial failures:

export async function getStats() {
  const [total, active, agg] = await Promise.all([
    prisma.campaign.count(),
    prisma.campaign.count({ where: { status: 'Active' } }),
    prisma.campaign.aggregate({
      _sum: { impressions: true, clicks: true, spentStroops: true },
    }),
  ]);
  // ...
}

Problem

If any one of the three queries fails (e.g., temporary connection issue, table lock), Promise.all() rejects immediately and discards results from successful queries. The route handler catches this, but the user gets a generic 500 error when partial data could have been returned.

Impact

  • Transient database issues cause the entire stats endpoint to fail
  • No degraded/partial response — it's all or nothing
  • The aggregate query is the most expensive and likely to timeout under load

Suggested Fix

Use Promise.allSettled() with fallback values:

export async function getStats() {
  const [totalResult, activeResult, aggResult] = await Promise.allSettled([
    prisma.campaign.count(),
    prisma.campaign.count({ where: { status: 'Active' } }),
    prisma.campaign.aggregate({
      _sum: { impressions: true, clicks: true, spentStroops: true },
    }),
  ]);

  return {
    total_campaigns: totalResult.status === 'fulfilled' ? totalResult.value : null,
    active_campaigns: activeResult.status === 'fulfilled' ? activeResult.value : null,
    total_impressions: aggResult.status === 'fulfilled' ? aggResult.value._sum.impressions ?? 0 : null,
    // ...
  };
}

File

backend/src/db/repositories/campaigns.ts — Lines 17-23

Metadata

Metadata

Assignees

No one assigned

    Labels

    backendNodejs Express backendbugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions