-
-
Notifications
You must be signed in to change notification settings - Fork 85
fix(stats): avoid extra apps query #1620
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
100ac4a
0bde263
fa9bebd
2d0496a
71bd735
e3d2dd3
20895b9
45c2277
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,16 +3,14 @@ import type { MiddlewareKeyVariables } from '../utils/hono.ts' | |
| import type { Database } from '../utils/supabase.types.ts' | ||
| import type { AppStats, StatsActions } from '../utils/types.ts' | ||
| import { greaterOrEqual, parse } from '@std/semver' | ||
| import { eq } from 'drizzle-orm' | ||
| import { Hono } from 'hono/tiny' | ||
| import { z } from 'zod/mini' | ||
| import { getAppStatus, setAppStatus } from '../utils/appStatus.ts' | ||
| import { getAppStatusPayload, setAppStatus } from '../utils/appStatus.ts' | ||
| import { BRES, simpleError, simpleError200, simpleRateLimit } from '../utils/hono.ts' | ||
| import { cloudlog } from '../utils/logging.ts' | ||
| import { sendNotifOrgCached } from '../utils/notifications.ts' | ||
| import { closeClient, ensurePlaceholderVersions, getAppOwnerPostgres, getAppVersionPostgres, getDrizzleClient, getPgClient } from '../utils/pg.ts' | ||
| import { makeDevice, parsePluginBody } from '../utils/plugin_parser.ts' | ||
| import * as schema from '../utils/postgres_schema.ts' | ||
| import { createStatsMau, createStatsVersion, onPremStats, sendStatsAndDevice } from '../utils/stats.ts' | ||
| import { backgroundTask, deviceIdRegex, INVALID_STRING_APP_ID, INVALID_STRING_DEVICE_ID, isLimited, MISSING_STRING_APP_ID, MISSING_STRING_DEVICE_ID, MISSING_STRING_PLATFORM, MISSING_STRING_VERSION_NAME, MISSING_STRING_VERSION_OS, NON_STRING_APP_ID, NON_STRING_DEVICE_ID, NON_STRING_PLATFORM, NON_STRING_VERSION_NAME, NON_STRING_VERSION_OS, reverseDomainRegex } from '../utils/utils.ts' | ||
| import { ALLOWED_STATS_ACTIONS } from './stats_actions.ts' | ||
|
|
@@ -21,18 +19,6 @@ z.config(z.locales.en()) | |
|
|
||
| const PLAN_ERROR = 'Cannot send stats, upgrade plan to continue to update' | ||
|
|
||
| async function allowDeviceCustomIdFromPg(drizzleClient: ReturnType<typeof getDrizzleClient>, app_id: string): Promise<boolean> { | ||
| const res = await drizzleClient | ||
| .select({ | ||
| allow_device_custom_id: schema.apps.allow_device_custom_id, | ||
| }) | ||
| .from(schema.apps) | ||
| .where(eq(schema.apps.app_id, app_id)) | ||
| .limit(1) | ||
|
|
||
| return res[0]?.allow_device_custom_id ?? true | ||
| } | ||
|
|
||
| export interface BatchStatsResult { | ||
| status: 'ok' | 'error' | ||
| error?: string | ||
|
|
@@ -88,23 +74,24 @@ async function post(c: Context, drizzleClient: ReturnType<typeof getDrizzleClien | |
| // Normalize once and use consistently for gating + persistence. | ||
| // Whitespace-only values are treated as "not provided". | ||
| device.custom_id = requestedCustomId === '' ? undefined : requestedCustomId | ||
| const hasCustomId = device.custom_id !== undefined | ||
|
|
||
| const planActions: Array<'mau' | 'bandwidth'> = ['mau', 'bandwidth'] | ||
| const cachedStatus = await getAppStatus(c, app_id) | ||
| const cached = await getAppStatusPayload(c, app_id) | ||
| const cachedStatus = cached?.status ?? null | ||
|
|
||
| if (cachedStatus === 'onprem') { | ||
| await onPremStats(c, app_id, action, device) | ||
| return { success: true, isOnprem: true } | ||
| } | ||
|
|
||
| const allowDeviceCustomId = device.custom_id === undefined ? true : await allowDeviceCustomIdFromPg(drizzleClient, app_id) | ||
|
|
||
| if (cachedStatus === 'cancelled') { | ||
| const statsActions: StatsActions[] = [{ action: 'needPlanUpgrade' }] | ||
| // Keep behavior backward compatible (default allow=true), but allow owners to | ||
| // disable custom_id persistence from unauthenticated /stats traffic. | ||
| if (!allowDeviceCustomId && device.custom_id !== undefined) { | ||
| const allowDeviceCustomId = hasCustomId ? (cached?.allow_device_custom_id ?? true) : true | ||
| if (!allowDeviceCustomId && hasCustomId) { | ||
| device.custom_id = undefined | ||
| statsActions.push({ action: 'customIdBlocked' }) | ||
| } | ||
| await sendStatsAndDevice(c, device, statsActions) | ||
| return { success: false, error: 'need_plan_upgrade', message: PLAN_ERROR } | ||
|
|
@@ -115,13 +102,14 @@ async function post(c: Context, drizzleClient: ReturnType<typeof getDrizzleClien | |
| await onPremStats(c, app_id, action, device) | ||
| return { success: true, isOnprem: true } | ||
| } | ||
|
|
||
| const allowDeviceCustomId = hasCustomId ? appOwner.allow_device_custom_id : true | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Useful? React with 👍 / 👎. |
||
| if (!appOwner.plan_valid) { | ||
| await setAppStatus(c, app_id, 'cancelled') | ||
| await setAppStatus(c, app_id, 'cancelled', { allow_device_custom_id: appOwner.allow_device_custom_id }) | ||
| cloudlog({ requestId: c.get('requestId'), message: 'Cannot update, upgrade plan to continue to update', id: app_id }) | ||
| const upgradeActions: StatsActions[] = [{ action: 'needPlanUpgrade' }] | ||
| if (!allowDeviceCustomId && device.custom_id !== undefined) { | ||
| if (!allowDeviceCustomId && hasCustomId) { | ||
| device.custom_id = undefined | ||
|
Comment on lines
+106
to
112
|
||
| upgradeActions.push({ action: 'customIdBlocked' }) | ||
| } | ||
| await sendStatsAndDevice(c, device, upgradeActions) | ||
| // Send weekly notification about missing payment (not configurable - payment related) | ||
|
|
@@ -132,9 +120,9 @@ async function post(c: Context, drizzleClient: ReturnType<typeof getDrizzleClien | |
| }, appOwner.owner_org, app_id, '0 0 * * 1', appOwner.orgs.management_email, drizzleClient)) // Weekly on Monday | ||
| return { success: false, error: 'need_plan_upgrade', message: 'Cannot update, upgrade plan to continue to update' } | ||
| } | ||
| await setAppStatus(c, app_id, 'cloud') | ||
| await setAppStatus(c, app_id, 'cloud', { allow_device_custom_id: appOwner.allow_device_custom_id }) | ||
| const statsActions: StatsActions[] = [] | ||
| if (!allowDeviceCustomId && device.custom_id !== undefined) { | ||
| if (!allowDeviceCustomId && hasCustomId) { | ||
| device.custom_id = undefined | ||
| statsActions.push({ action: 'customIdBlocked' }) | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -85,7 +85,7 @@ export async function updateWithPG( | |
| return onPremStats(c, app_id, 'get', device) | ||
| } | ||
| if (!appOwner.plan_valid) { | ||
| await setAppStatus(c, app_id, 'cancelled') | ||
| await setAppStatus(c, app_id, 'cancelled', { allow_device_custom_id: appOwner.allow_device_custom_id }) | ||
| cloudlog({ requestId: c.get('requestId'), message: 'Cannot update, upgrade plan to continue to update', id: app_id }) | ||
| await sendStatsAndDevice(c, device, [{ action: 'needPlanUpgrade' }]) | ||
| // Send weekly notification about missing payment (not configurable - payment related) | ||
|
|
@@ -96,7 +96,7 @@ export async function updateWithPG( | |
| }, appOwner.owner_org, app_id, '0 0 * * 1', appOwner.orgs.management_email, drizzleClient)) // Weekly on Monday | ||
| return c.json({ error: 'on_premise_app', message: 'On-premise app detected' }, 429) | ||
| } | ||
| await setAppStatus(c, app_id, 'cloud') | ||
| await setAppStatus(c, app_id, 'cloud', { allow_device_custom_id: appOwner.allow_device_custom_id }) | ||
|
Comment on lines
88
to
+99
|
||
| const channelDeviceCount = appOwner.channel_device_count ?? 0 | ||
| const manifestBundleCount = appOwner.manifest_bundle_count ?? 0 | ||
| const bypassChannelOverrides = channelDeviceCount <= 0 | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
appOwner.allow_device_custom_idis accessed here, butgetAppOwnerPostgres()currently does not select/return that column (see utils/pg.ts). This should fail TypeScript and will make the cache payload/enforcement incorrect at runtime. UpdategetAppOwnerPostgres()to includeallow_device_custom_id(ideally preserving the previous replica-safe fallback semantics).