Files
zpan/workers/scheduled.ts
T
Jasper Van c85e60f200 fix(analytics): enforce trustworthy offline statistics (#510)
* fix(analytics): enforce trustworthy offline statistics

Separate immutable counters from point-in-time snapshots, expose incomplete coverage instead of synthetic zeroes, and keep browser analytics result-only.

Restore finite Free quota baselines, fail closed for invalid storage quota, reconcile traffic reports fairly, and add production-safe backfill and data-quality diagnostics.

* fix(analytics): preserve global backfill totals

Group generated hourly backfill rows by their projected values so SQLite cannot resolve output aliases to source organization columns and overwrite cross-organization totals.
2026-07-20 10:23:22 -04:00

73 lines
2.6 KiB
TypeScript

// CF Workers scheduled() handler.
import { createQuotaRepo } from '../server/adapters/repos/quota'
import { createDeps } from '../server/composition'
import { createCloudflarePlatform } from '../server/platform/cloudflare'
import { syncPendingRemoteDownloadUsageReports } from '../server/usecases/downloads/remote-download-usage'
import { purgeExpiredTrash, resolveTrashRetentionDays } from '../server/usecases/object'
import { INSTANCE_TELEMETRY_CRON, reportInstanceTelemetry } from '../server/usecases/site/instance-telemetry'
import { runLicensingRefresh } from '../server/usecases/site/licensing'
import { syncPendingCloudTrafficReports } from '../server/usecases/store/traffic-metering'
import { ZPAN_CLOUD_URL_DEFAULT } from '../shared/constants'
// Subset of the worker Env used by the scheduled handler.
// The full Env is defined in bootstrap.ts; this avoids circular imports.
export interface ScheduledEnv {
DB: D1Database
ZPAN_CLOUD_URL?: string
ZPAN_TELEMETRY_ALLOW_IP?: string
ZPAN_TRASH_RETENTION_DAYS?: string
[key: string]: unknown
}
const TRAFFIC_SYNC_CRON = '*/10 * * * *'
const QUOTA_RESET_CRON = '0 0 1 * *'
const TRASH_PURGE_CRON = '0 4 * * *'
type ScheduledTrigger = Pick<ScheduledEvent, 'cron'>
function envAllowsIp(value: string | undefined): boolean {
return !['0', 'false', 'no', 'off'].includes(value?.trim().toLowerCase() ?? '')
}
export async function handleScheduled(event: ScheduledTrigger, env: ScheduledEnv): Promise<void> {
const platform = createCloudflarePlatform(env)
const deps = createDeps(platform)
const cloudBaseUrl = env.ZPAN_CLOUD_URL ?? ZPAN_CLOUD_URL_DEFAULT
if (event.cron === TRAFFIC_SYNC_CRON) {
await deps.quota.reconcileFreePlanBaselines()
await Promise.all([
syncPendingCloudTrafficReports(deps, { cloudBaseUrl }),
syncPendingRemoteDownloadUsageReports(deps, { cloudBaseUrl }),
deps.adminStats.refreshHourlyRollups(new Date()),
])
return
}
if (event.cron === QUOTA_RESET_CRON) {
await createQuotaRepo(platform.db).resetExpiredTrafficQuotas()
return
}
if (event.cron === TRASH_PURGE_CRON) {
await purgeExpiredTrash(deps, resolveTrashRetentionDays(env.ZPAN_TRASH_RETENTION_DAYS))
return
}
if (event.cron === INSTANCE_TELEMETRY_CRON) {
await reportInstanceTelemetry(deps, {
config: {
allowIp: envAllowsIp(env.ZPAN_TELEMETRY_ALLOW_IP),
},
cron: event.cron,
trigger: 'scheduled',
runtime: {
runtime: 'workerd',
platform: 'cloudflare-workers',
},
})
return
}
await runLicensingRefresh(deps, cloudBaseUrl)
}