Files
zpan/workers/scheduled.ts
T
Jasper Van 1d58d5b80d feat(image-hosting): add configurable custom domain providers (#529)
* feat(image-hosting): add custom domain providers

* test(image-hosting): cover custom domain provider flows
2026-07-27 22:52:18 -04:00

86 lines
3.0 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 { purgeExpiredResourceChanges } from '../server/usecases/resource-changes'
import { reconcileImageDomains } from '../server/usecases/site/image-domain-provider'
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 STATS_ROLLUP_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 }),
])
return
}
if (event.cron === STATS_ROLLUP_CRON) {
const now = new Date()
await Promise.all([
deps.adminStats.refreshHourlyRollups(now),
deps.webdavState.purgeExpiredLocks(),
purgeExpiredResourceChanges(deps, now),
reconcileImageDomains(deps),
])
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)
}