Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions supabase/functions/_backend/plugin_runtime/utils/cloudflare.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1872,8 +1872,15 @@ export async function getUpdateStatsCF(c: Context): Promise<UpdateStats> {
const result = await runQueryToCFA<{ app_id: string, failed: number, set: number, get: number }>(c, query)

cloudlog({ requestId: c.get('requestId'), message: 'getUpdateStatsCF result', result })
const total = result.reduce((acc, app) => {
acc.failed += app.failed || 0
acc.set += app.set || 0
acc.get += app.get || 0
return acc
}, { failed: 0, set: 0, get: 0 })

const apps = result
.filter(app => app.get > 0)
.filter(app => (app.set + app.failed) > 0)
.map((app) => {
const totalOutcomes = app.set + app.failed
const successRate = Number(Number(totalOutcomes > 0 ? (app.set / totalOutcomes) * 100 : 100).toFixed(2))
Expand All @@ -1884,13 +1891,6 @@ export async function getUpdateStatsCF(c: Context): Promise<UpdateStats> {
}
})

const total = apps.reduce((acc, app) => {
acc.failed += app.failed
acc.set += app.set
acc.get += app.get
return acc
}, { failed: 0, set: 0, get: 0 })

const totalOutcomes = total.set + total.failed
const totalSuccessRate = totalOutcomes > 0 ? (total.set / totalOutcomes) * 100 : 100

Expand Down Expand Up @@ -2837,7 +2837,7 @@ function buildBreakdownMetrics(
}

export async function getPublicLiveUpdateMetricsCF(c: Context, referenceDate = new Date()): Promise<PublicLiveUpdateMetrics> {
if (!c.env.APP_LOG || !c.env.VERSION_USAGE || !c.env.DEVICE_USAGE || !c.env.DEVICE_INFO || !getEnv(c, 'CF_ANALYTICS_TOKEN') || !getEnv(c, 'CF_ACCOUNT_ANALYTICS_ID'))
if (!c.env.APP_LOG || !c.env.DEVICE_USAGE || !c.env.DEVICE_INFO || !getEnv(c, 'CF_ANALYTICS_TOKEN') || !getEnv(c, 'CF_ACCOUNT_ANALYTICS_ID'))
throw new Error('Public live update metric bindings are unavailable')

const end = new Date(Date.UTC(referenceDate.getUTCFullYear(), referenceDate.getUTCMonth(), referenceDate.getUTCDate()))
Expand All @@ -2847,7 +2847,7 @@ export async function getPublicLiveUpdateMetricsCF(c: Context, referenceDate = n
const failureActions = PUBLIC_FAILURE_ACTIONS.map(action => `'${action}'`).join(', ')
const day = `formatDateTime(toStartOfInterval(timestamp, INTERVAL '1' DAY), '%Y-%m-%d')`
const appLogOutcomeFilter = `(blob2 = 'set' OR blob2 IN (${failureActions}))`
const dailySuccessQuery = `SELECT ${day} AS date, sum(if(blob3 = 'install', 1, 0)) AS installs, sum(if(blob3 = 'fail', 1, 0)) AS fails FROM version_usage WHERE ${window} GROUP BY date ORDER BY date ASC`
const dailySuccessQuery = `SELECT ${day} AS date, sum(if(blob2 = 'set', 1, 0)) AS installs, sum(if(blob2 IN (${failureActions}), 1, 0)) AS fails FROM app_log WHERE ${window} AND ${appLogOutcomeFilter} GROUP BY date ORDER BY date ASC`
const failuresQuery = `SELECT action, count() AS devices FROM (SELECT ${day} AS date, blob2 AS action, index1 AS app_id, blob1 AS device_id FROM app_log WHERE ${window} AND blob2 IN (${failureActions}) GROUP BY date, action, app_id, device_id) GROUP BY action`
const platformsShareQuery = `SELECT platform, count() AS devices FROM (SELECT double1 AS platform, index1 AS app_id, blob1 AS device_id FROM device_usage WHERE ${window} AND double1 IN (0.0, 1.0, 2.0) GROUP BY platform, app_id, device_id) GROUP BY platform`
const platformsOutcomeQuery = `SELECT blob5 AS key, sum(if(blob2 = 'set', 1, 0)) AS successes, sum(if(blob2 IN (${failureActions}), 1, 0)) AS failures FROM app_log WHERE ${window} AND ${appLogOutcomeFilter} AND blob5 IN ('ios', 'android', 'electron') GROUP BY blob5`
Expand Down
20 changes: 10 additions & 10 deletions supabase/functions/_backend/utils/cloudflare.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2121,8 +2121,15 @@ export async function getUpdateStatsCF(c: Context): Promise<UpdateStats> {
const result = await runQueryToCFA<{ app_id: string, failed: number, set: number, get: number }>(c, query)

cloudlog({ requestId: c.get('requestId'), message: 'getUpdateStatsCF result', result })
const total = result.reduce((acc, app) => {
acc.failed += app.failed || 0
acc.set += app.set || 0
acc.get += app.get || 0
return acc
}, { failed: 0, set: 0, get: 0 })

const apps = result
.filter(app => app.get > 0)
.filter(app => (app.set + app.failed) > 0)
.map((app) => {
const totalOutcomes = app.set + app.failed
const successRate = Number(Number(totalOutcomes > 0 ? (app.set / totalOutcomes) * 100 : 100).toFixed(2))
Expand All @@ -2133,13 +2140,6 @@ export async function getUpdateStatsCF(c: Context): Promise<UpdateStats> {
}
})

const total = apps.reduce((acc, app) => {
acc.failed += app.failed
acc.set += app.set
acc.get += app.get
return acc
}, { failed: 0, set: 0, get: 0 })

const totalOutcomes = total.set + total.failed
const totalSuccessRate = totalOutcomes > 0 ? (total.set / totalOutcomes) * 100 : 100

Expand Down Expand Up @@ -3086,7 +3086,7 @@ function buildBreakdownMetrics(
}

export async function getPublicLiveUpdateMetricsCF(c: Context, referenceDate = new Date()): Promise<PublicLiveUpdateMetrics> {
if (!c.env.APP_LOG || !c.env.VERSION_USAGE || !c.env.DEVICE_USAGE || !c.env.DEVICE_INFO || !getEnv(c, 'CF_ANALYTICS_TOKEN') || !getEnv(c, 'CF_ACCOUNT_ANALYTICS_ID'))
if (!c.env.APP_LOG || !c.env.DEVICE_USAGE || !c.env.DEVICE_INFO || !getEnv(c, 'CF_ANALYTICS_TOKEN') || !getEnv(c, 'CF_ACCOUNT_ANALYTICS_ID'))
throw new Error('Public live update metric bindings are unavailable')

const end = new Date(Date.UTC(referenceDate.getUTCFullYear(), referenceDate.getUTCMonth(), referenceDate.getUTCDate()))
Expand All @@ -3096,7 +3096,7 @@ export async function getPublicLiveUpdateMetricsCF(c: Context, referenceDate = n
const failureActions = PUBLIC_FAILURE_ACTIONS.map(action => `'${action}'`).join(', ')
const day = `formatDateTime(toStartOfInterval(timestamp, INTERVAL '1' DAY), '%Y-%m-%d')`
const appLogOutcomeFilter = `(blob2 = 'set' OR blob2 IN (${failureActions}))`
const dailySuccessQuery = `SELECT ${day} AS date, sum(if(blob3 = 'install', 1, 0)) AS installs, sum(if(blob3 = 'fail', 1, 0)) AS fails FROM version_usage WHERE ${window} GROUP BY date ORDER BY date ASC`
const dailySuccessQuery = `SELECT ${day} AS date, sum(if(blob2 = 'set', 1, 0)) AS installs, sum(if(blob2 IN (${failureActions}), 1, 0)) AS fails FROM app_log WHERE ${window} AND ${appLogOutcomeFilter} GROUP BY date ORDER BY date ASC`
const failuresQuery = `SELECT action, count() AS devices FROM (SELECT ${day} AS date, blob2 AS action, index1 AS app_id, blob1 AS device_id FROM app_log WHERE ${window} AND blob2 IN (${failureActions}) GROUP BY date, action, app_id, device_id) GROUP BY action`
const platformsShareQuery = `SELECT platform, count() AS devices FROM (SELECT double1 AS platform, index1 AS app_id, blob1 AS device_id FROM device_usage WHERE ${window} AND double1 IN (0.0, 1.0, 2.0) GROUP BY platform, app_id, device_id) GROUP BY platform`
const platformsOutcomeQuery = `SELECT blob5 AS key, sum(if(blob2 = 'set', 1, 0)) AS successes, sum(if(blob2 IN (${failureActions}), 1, 0)) AS failures FROM app_log WHERE ${window} AND ${appLogOutcomeFilter} AND blob5 IN ('ios', 'android', 'electron') GROUP BY blob5`
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
CREATE OR REPLACE FUNCTION "public"."get_update_stats"() RETURNS TABLE("app_id" character varying, "failed" bigint, "install" bigint, "get" bigint, "success_rate" numeric, "healthy" boolean)
LANGUAGE "plpgsql" SECURITY DEFINER
SET "search_path" TO ''
AS $$
BEGIN
RETURN QUERY
WITH stats AS (
SELECT
version_usage.app_id,
COALESCE(SUM(CASE WHEN action = 'fail' THEN 1 ELSE 0 END), 0) AS failed,
COALESCE(SUM(CASE WHEN action = 'install' THEN 1 ELSE 0 END), 0) AS install,
COALESCE(SUM(CASE WHEN action = 'get' THEN 1 ELSE 0 END), 0) AS get
FROM
public.version_usage
WHERE
timestamp >= (date_trunc('minute', now()) - INTERVAL '10 minutes')
AND timestamp < (date_trunc('minute', now()) - INTERVAL '9 minutes')
GROUP BY
version_usage.app_id
)
SELECT
stats.app_id,
stats.failed,
stats.install,
stats.get,
CASE
WHEN (stats.install + stats.failed) > 0 THEN
ROUND((stats.install::numeric / (stats.install + stats.failed)) * 100, 2)
ELSE 100
END AS success_rate,
CASE
WHEN (stats.install + stats.failed) > 0 THEN
((stats.install::numeric / (stats.install + stats.failed)) * 100 >= 70)
ELSE true
END AS healthy
FROM
stats
WHERE
(stats.install + stats.failed) > 0;
END;
$$;

ALTER FUNCTION "public"."get_update_stats"() OWNER TO "postgres";
5 changes: 2 additions & 3 deletions tests/public-live-update-metrics.unit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ function createContext() {
return {
env: {
APP_LOG: {},
VERSION_USAGE: {},
DEVICE_USAGE: {},
DEVICE_INFO: {},
CF_ANALYTICS_TOKEN: 'analytics-token',
Expand Down Expand Up @@ -45,7 +44,7 @@ describe('public live update metrics', () => {
const query = String(init?.body ?? '')
queries.push(query)

if (query.includes('FROM version_usage') && query.includes('AS installs')) {
if (query.includes('FROM app_log') && query.includes('AS installs') && query.includes('GROUP BY date')) {
return analyticsResponse(
[
{ name: 'date', type: 'String' },
Expand Down Expand Up @@ -210,7 +209,7 @@ describe('public live update metrics', () => {
expect(metrics.updater_versions[0]).toMatchObject({ key: '8.1.0', share: 60 })
expect(metrics.updater_versions.find(row => row.key === '8.1.0')?.success_rate).toBe(93.3)
expect(queries.length).toBe(11)
expect(queries.join('\n')).toContain('FROM version_usage')
expect(queries.join('\n')).toContain('FROM app_log')
expect(queries.join('\n')).toContain('blob6')
expect(queries.join('\n')).toContain('blob7')
expect(queries.join('\n')).toContain('blob10')
Expand Down
Loading