Bernt Christian Egeland пре 3 недеља
родитељ
комит
eb79f13d03

+ 42 - 0
src/__tests__/cron/tick-summary.test.ts

@@ -0,0 +1,42 @@
+import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
+import { createTickSummary } from '@/lib/cron/tick-summary'
+
+describe('createTickSummary', () => {
+  beforeEach(() => {
+    vi.useFakeTimers()
+    vi.setSystemTime(new Date('2026-10-08T10:00:00Z'))
+    vi.spyOn(console, 'warn').mockImplementation(() => undefined)
+  })
+  afterEach(() => {
+    vi.useRealTimers()
+    vi.restoreAllMocks()
+  })
+
+  it('stays silent on per-tick work and prints one hourly total', () => {
+    const summary = createTickSummary('Integration jobs processed')
+    for (let i = 0; i < 59; i++) {
+      summary.add(1)
+      vi.advanceTimersByTime(60_000)
+    }
+    expect(console.warn).not.toHaveBeenCalled()
+    vi.advanceTimersByTime(60_000)
+    summary.add(1)
+    expect(console.warn).toHaveBeenCalledTimes(1)
+    expect(console.warn).toHaveBeenCalledWith(
+      '[cron] Integration jobs processed: 60 in 60 run(s) over the last 60 min'
+    )
+  })
+
+  it('ignores idle ticks and resets after a summary', () => {
+    const summary = createTickSummary('Webhook deliveries processed')
+    summary.add(0)
+    summary.add(3)
+    vi.advanceTimersByTime(2 * 60 * 60 * 1000)
+    summary.add(2)
+    expect(console.warn).toHaveBeenCalledWith(
+      '[cron] Webhook deliveries processed: 5 in 2 run(s) over the last 120 min'
+    )
+    summary.add(1)
+    expect(console.warn).toHaveBeenCalledTimes(1)
+  })
+})

+ 3 - 2
src/lib/cron/integration-jobs.ts

@@ -1,4 +1,5 @@
 import { CronJob } from 'cron'
+import { createTickSummary } from './tick-summary'
 import {
   cleanupIntegrationHistory,
   recoverStuckJobs,
@@ -11,13 +12,13 @@ import {
  * left running, queue the timed syncs that are due, then run due jobs.
  */
 export function processIntegrationJobs() {
+  const summary = createTickSummary('Integration jobs processed')
   const job = new CronJob('* * * * *', async () => {
     try {
       const recovered = await recoverStuckJobs()
       if (recovered > 0) console.warn(`[cron] Recovered ${recovered} stuck integration jobs`)
       await scheduleDueSyncs()
-      const ran = await runDueJobs(50)
-      if (ran > 0) console.warn(`[cron] Integration jobs processed: ${ran}`)
+      summary.add(await runDueJobs(50))
     } catch (err) {
       console.error('[cron] Integration job runner failed:', err)
     }

+ 26 - 0
src/lib/cron/tick-summary.ts

@@ -0,0 +1,26 @@
+/**
+ * Every-minute crons used to print one line per tick that did work, which on
+ * a busy install is a line a minute of "processed: 1". Routine work is already
+ * recorded per item (integration logs, delivery rows), so the console only
+ * needs an hourly total. Failures and recoveries still log immediately.
+ */
+const SUMMARY_MS = 60 * 60 * 1000
+
+export function createTickSummary(label: string, intervalMs = SUMMARY_MS) {
+  let total = 0
+  let ticks = 0
+  let since = Date.now()
+  return {
+    add(count: number) {
+      if (count <= 0) return
+      total += count
+      ticks++
+      if (Date.now() - since < intervalMs) return
+      const minutes = Math.round((Date.now() - since) / 60_000)
+      console.warn(`[cron] ${label}: ${total} in ${ticks} run(s) over the last ${minutes} min`)
+      total = 0
+      ticks = 0
+      since = Date.now()
+    },
+  }
+}

+ 3 - 4
src/lib/cron/webhook-deliveries.ts

@@ -1,6 +1,7 @@
 import { CronJob } from 'cron'
 import { db } from '@/lib/db'
 import { processDueDeliveries, recoverStuckDeliveries } from '@/features/webhooks/Lib/deliver'
+import { createTickSummary } from './tick-summary'
 
 /**
  * Webhook delivery retry cron — runs every minute. First sweeps any
@@ -8,16 +9,14 @@ import { processDueDeliveries, recoverStuckDeliveries } from '@/features/webhook
  * picks up due retries and re-attempts them with HMAC signing.
  */
 export function processWebhookDeliveries() {
+  const summary = createTickSummary('Webhook deliveries processed')
   const job = new CronJob('* * * * *', async () => {
     try {
       const recovered = await recoverStuckDeliveries()
       if (recovered > 0) {
         console.warn(`[cron] Recovered ${recovered} stuck webhook deliveries`)
       }
-      const count = await processDueDeliveries(100)
-      if (count > 0) {
-        console.warn(`[cron] Webhook deliveries processed: ${count}`)
-      }
+      summary.add(await processDueDeliveries(100))
     } catch (err) {
       console.error('[cron] Webhook delivery processor failed:', err)
     }