fix(cron): keep global stats snapshots running#2484
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughReplaces the monolithic LogSnag global-stats computation with a pgmq-backed sharded snapshot pipeline persisted in ChangesSharded Global Stats Pipeline
Sequence Diagram(s)sequenceDiagram
rect rgba(70, 130, 180, 0.5)
Note over Trigger,pgmq: Dispatcher invocation
Trigger->>logsnag_insights app: POST /logsnag_insights
logsnag_insights app->>pgmq: reserve next retry message
logsnag_insights app->>EdgeRuntime: waitUntil(scheduleLogsnagInsightsUpdate)
logsnag_insights app-->>Trigger: HTTP 202
end
rect rgba(60, 179, 113, 0.5)
Note over EdgeRuntime,global_stats: Background shard scheduling
EdgeRuntime->>global_stats: upsert row for date_id, reset completed_shards
EdgeRuntime->>global_stats: read completed_shards
EdgeRuntime->>EdgeRuntime: compute missing required shards
loop each missing shard
EdgeRuntime->>pgmq: enqueue logsnag_insights_<shard> with delay
end
EdgeRuntime->>pgmq: cancel reserved retry (on success)
end
rect rgba(210, 105, 30, 0.5)
Note over pgmq,global_stats: Per-shard execution
pgmq->>ShardRunner: POST /logsnag_insights_<shard>
ShardRunner->>CloudflareAnalytics: query with referenceDate window
ShardRunner->>SupabaseRPC: query plan/org counts
ShardRunner->>global_stats: patch shard fields
ShardRunner->>global_stats: mark shard complete in completed_shards
ShardRunner->>TrackingLogSnag: send events (strict mode)
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~75 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
Merging this PR will not alter performance
Comparing Footnotes
|
5309d18 to
2eab7d2
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2eab7d2668
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
2eab7d2 to
6599525
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6599525296
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
6599525 to
ab2c638
Compare
ab2c638 to
aa7b5d9
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: aa7b5d9c4f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
aa7b5d9 to
350bfaf
Compare
350bfaf to
83ff4db
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 83ff4db9cd
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
83ff4db to
3beacac
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3beacac22d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
3beacac to
a3ec396
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a3ec396759
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
a3ec396 to
8d0e6d0
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8d0e6d01b2
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
8d0e6d0 to
bf7017c
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@tests/logsnag-insights-revenue.unit.test.ts`:
- Around line 246-248: The `.then()` callback used on line 247 for handling the
app request response violates the async/await requirement for TypeScript files.
Replace the Promise.resolve().then() pattern with async/await syntax by
converting the callback that extracts response.status into an async arrow
function or IIFE that awaits the app.request call and returns the status
property, ensuring it integrates properly with the Promise.race() call.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 27d51e83-bf0f-4fe7-b9a2-24fb99b37129
📒 Files selected for processing (8)
supabase/functions/_backend/triggers/logsnag_insights.tssupabase/functions/_backend/utils/cloudflare.tssupabase/functions/_backend/utils/logsnag.tssupabase/functions/_backend/utils/tracking.tssupabase/functions/triggers/index.tssupabase/migrations/20260611160348_add_global_stats_completed_shards.sqltests/cloudflare-datetime.unit.test.tstests/logsnag-insights-revenue.unit.test.ts
🔗 Linked repositories identified
CodeRabbit considers these linked repositories for cross-repo context during reviews:
Cap-go/capacitor-updater(manual)
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
supabase/functions/_backend/triggers/logsnag_insights.ts (1)
1230-1304: 🛠️ Refactor suggestion | 🟠 MajorReplace
.then()chains withasync/awaitin TS shard logic.The Promise pipelines in these ranges rely on chained
.then()callbacks; TypeScript code must useasync/awaitstyle per coding guidelines.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@supabase/functions/_backend/triggers/logsnag_insights.ts` around lines 1230 - 1304, The Promise.all() array contains multiple Promise chains using .then() callbacks instead of async/await style, which violates the TypeScript coding guidelines. Convert all .then() chains in the array (used with countAllApps, countAllUpdates, countAllUpdatesExternal, users query, orgs query, getGithubStars, get_customer_counts RPC, paying_orgs_for_conversion query, count_all_onboarded RPC, count_all_need_upgrade RPC, count_all_plans_v2 RPC, and readActiveAppsCF) to use async/await syntax by either extracting each promise chain into separate async helper functions or wrapping the Promise.all() logic in an async IIFE, ensuring error handling and return values remain consistent.Source: Coding guidelines
♻️ Duplicate comments (1)
tests/logsnag-insights-revenue.unit.test.ts (1)
247-247:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winReplace
.then()with async/await in this TypeScript test path (Line 247).This line still uses a
.then()callback; the repository TypeScript guideline requires async/await for promise handling.Suggested patch
const requestTimeoutMs = 500 + const responseStatusPromise = (async () => { + const response = await app.request('http://localhost/', { method: 'POST' }) + return response.status + })() const result = await Promise.race([ - Promise.resolve(app.request('http://localhost/', { method: 'POST' })).then((response: Response) => response.status), + responseStatusPromise, new Promise<'timeout'>(resolve => setTimeout(() => resolve('timeout'), requestTimeoutMs)), ])As per coding guidelines, TypeScript promise handling should use async/await instead of
.then()callbacks.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/logsnag-insights-revenue.unit.test.ts` at line 247, The Promise.resolve().then() chain at the app.request call is using callback-based promise handling instead of async/await syntax required by the repository's TypeScript guidelines. Refactor this line to use async/await pattern by moving it into an async function context, awaiting the app.request call, and then accessing the response.status property directly on the awaited result instead of chaining with .then().Source: Coding guidelines
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@supabase/functions/_backend/triggers/logsnag_insights.ts`:
- Around line 1387-1417: The local variables in the Promise.all destructuring
assignment use snake_case naming (updates_last_month, devices_last_month,
devices_by_platform, registers_today, bundle_storage_gb, success_rate,
demo_apps_created) which violates TypeScript/JavaScript conventions that require
camelCase for local identifiers. Convert all these variable names to camelCase
(updatesLastMonth, devicesLastMonth, devicesByPlatform, registersToday,
bundleStorageGb, successRate, demoAppsCreated) in the destructuring assignment,
and then update all corresponding references to these variables throughout the
block, including in the updateGlobalStatsSnapshot function call where these
variables are passed as object properties. Note: keep the object property keys
in the updateGlobalStatsSnapshot call as snake_case to match the database column
names.
- Line 1813: The current instance creation in logsnag_insights.ts uses `new
Hono<MiddlewareKeyVariables>()` which is inconsistent with the guideline
recommending `createHono` from `utils/hono.ts`. However, since this pattern is
used across nearly all backend files (triggers, plugins, private directories)
and only `admin_credits.ts` uses `createHono`, a decision is needed: either
refactor the codebase to standardize on `createHono` across all backend handlers
to ensure request-context middleware is applied consistently, or clarify the
guideline on when `createHono` is required versus the direct pattern. If
proceeding with standardization, replace the `new
Hono<MiddlewareKeyVariables>()` instantiation with the result of calling
`createHono()`, ensuring the import from `utils/hono.ts` is added, and apply
this change codebase-wide across all backend handler files.
In `@tests/cloudflare-datetime.unit.test.ts`:
- Around line 13-18: The test for the getLastMonthAnalyticsWindow function is
currently nested inside the describe('formatDateCF') block, but it should have
its own describe block for better test organization and clarity. Extract this
test by creating a new describe block specifically for
getLastMonthAnalyticsWindow tests and move the it.concurrent test into that new
describe block, keeping the test logic unchanged.
---
Outside diff comments:
In `@supabase/functions/_backend/triggers/logsnag_insights.ts`:
- Around line 1230-1304: The Promise.all() array contains multiple Promise
chains using .then() callbacks instead of async/await style, which violates the
TypeScript coding guidelines. Convert all .then() chains in the array (used with
countAllApps, countAllUpdates, countAllUpdatesExternal, users query, orgs query,
getGithubStars, get_customer_counts RPC, paying_orgs_for_conversion query,
count_all_onboarded RPC, count_all_need_upgrade RPC, count_all_plans_v2 RPC, and
readActiveAppsCF) to use async/await syntax by either extracting each promise
chain into separate async helper functions or wrapping the Promise.all() logic
in an async IIFE, ensuring error handling and return values remain consistent.
---
Duplicate comments:
In `@tests/logsnag-insights-revenue.unit.test.ts`:
- Line 247: The Promise.resolve().then() chain at the app.request call is using
callback-based promise handling instead of async/await syntax required by the
repository's TypeScript guidelines. Refactor this line to use async/await
pattern by moving it into an async function context, awaiting the app.request
call, and then accessing the response.status property directly on the awaited
result instead of chaining with .then().
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 1e576883-41f1-482a-b2fa-6ae29940c5fe
📒 Files selected for processing (8)
supabase/functions/_backend/triggers/logsnag_insights.tssupabase/functions/_backend/utils/cloudflare.tssupabase/functions/_backend/utils/logsnag.tssupabase/functions/_backend/utils/tracking.tssupabase/functions/triggers/index.tssupabase/migrations/20260615112920_add_global_stats_completed_shards.sqltests/cloudflare-datetime.unit.test.tstests/logsnag-insights-revenue.unit.test.ts
🔗 Linked repositories identified
CodeRabbit considers these linked repositories for cross-repo context during reviews:
Cap-go/capacitor-updater(manual)
c2f3a8d to
5fe173e
Compare
5fe173e to
649d4c9
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 649d4c94e5
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
supabase/functions/_backend/triggers/logsnag_insights.ts (2)
381-451:⚠️ Potential issue | 🟠 Major | ⚡ Quick winPropagate required-shard data-source failures so retries can work.
These required shard paths log provider/DB errors and then return zero/default values. Since
runLogsnagInsightsShard()marks a shard complete after the runner returns, transient failures can be persisted as a completed snapshot and the queue will not retry the failed shard. Throw on query/provider errors; only write zero for successful empty results.Also applies to: 531-548, 1289-1325
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@supabase/functions/_backend/triggers/logsnag_insights.ts` around lines 381 - 451, The issue is that when database queries fail in the required shard data-sources, the code logs the error and returns default zero values, causing `runLogsnagInsightsShard()` to mark the shard as complete despite the failure. Transient failures then get persisted as completed snapshots and won't be retried. Instead of returning default values when plansError or subsError occur, throw the error to propagate the failure up to the retry logic. Only return the default zero-value objects when the queries succeed but return empty data (when plansData or subsData is null/empty due to a successful empty result, not due to an error). This pattern needs to be applied at all three affected locations: the plansError block in the shown diff, the subsError block in the shown diff, and the two additional error-handling blocks mentioned in the consolidated sites at line ranges 531-548 and 1289-1325.
1263-1337:⚠️ Potential issue | 🟠 MajorReplace
.then()callbacks withasync/awaitto comply with TypeScript guidelines.The code contains multiple promise callback chains violating the guideline that requires
async/awaitinstead of.then()callbacks in TypeScript files. Lines 1263–1337 include 7+.then()chains (lines 1283, 1287, 1289, 1299, 1306, 1311, 1316, 1320, 1327), and lines 1461–1546 contain 5+ additional instances (lines 1488, 1505, 1517, 1529, 1541). Refactor these Promise.all entries using async helpers or IIFEs to maintain consistency with the codebase style.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@supabase/functions/_backend/triggers/logsnag_insights.ts` around lines 1263 - 1337, The Promise.all() array contains multiple `.then()` callback chains that should be replaced with async/await syntax to comply with TypeScript guidelines. Refactor each promise entry that uses `.then()` (such as the chains on the supabase queries for users, orgs, customers, paying_orgs_for_conversion, onboarded, need_upgrade, plans, and actives, as well as the readActiveAppsCF call) by wrapping them in async helper functions or IIFEs that use async/await instead of chaining .then() callbacks. This will make the code more consistent with the codebase style and modern TypeScript practices.Source: Coding guidelines
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@supabase/functions/_backend/triggers/logsnag_insights.ts`:
- Around line 190-195: The function `readLogsnagInsightsPayload()` currently
silently converts JSON parse failures to an empty object, which causes malformed
non-empty payloads to use default values instead of rejecting them. Modify the
function to distinguish between truly empty request bodies (which should return
an empty object) and non-empty bodies with invalid JSON (which should return a
400 error response). Check the raw request body content before attempting to
parse it, and reject with a 400 status code when the body is non-empty but
contains invalid JSON.
- Around line 1280-1287: The queries on the users and orgs tables are using
.select('*', { count: 'exact' }) which fetches full row payloads in addition to
the count, creating unnecessary overhead on large tables. Replace both of these
inefficient queries with Supabase's count-only approach by using head: true
instead, matching the pattern already used elsewhere in this file. This applies
to both the supabase.from('users') query and the supabase.from('orgs') query to
ensure only count data is requested without fetching row payloads.
In `@supabase/functions/_backend/utils/cloudflare.ts`:
- Around line 1009-1014: The fallback rolling-window calculation is losing
precision by truncating the ISO datetime to just the date portion using slice(0,
10), which drops the time-of-day and causes the window to start from midnight
instead of the exact timestamp 30 days ago. This can result in queries spanning
up to 31 days instead of a true rolling 30-day window. Modify the oneMonthAgo
variable construction to preserve the full ISO datetime format (without slicing
to just YYYY-MM-DD) when formatting the startExpression, ensuring the rolling
window is exactly LAST_MONTH_ANALYTICS_WINDOW_MS milliseconds and not widened by
calendar day boundaries.
---
Outside diff comments:
In `@supabase/functions/_backend/triggers/logsnag_insights.ts`:
- Around line 381-451: The issue is that when database queries fail in the
required shard data-sources, the code logs the error and returns default zero
values, causing `runLogsnagInsightsShard()` to mark the shard as complete
despite the failure. Transient failures then get persisted as completed
snapshots and won't be retried. Instead of returning default values when
plansError or subsError occur, throw the error to propagate the failure up to
the retry logic. Only return the default zero-value objects when the queries
succeed but return empty data (when plansData or subsData is null/empty due to a
successful empty result, not due to an error). This pattern needs to be applied
at all three affected locations: the plansError block in the shown diff, the
subsError block in the shown diff, and the two additional error-handling blocks
mentioned in the consolidated sites at line ranges 531-548 and 1289-1325.
- Around line 1263-1337: The Promise.all() array contains multiple `.then()`
callback chains that should be replaced with async/await syntax to comply with
TypeScript guidelines. Refactor each promise entry that uses `.then()` (such as
the chains on the supabase queries for users, orgs, customers,
paying_orgs_for_conversion, onboarded, need_upgrade, plans, and actives, as well
as the readActiveAppsCF call) by wrapping them in async helper functions or
IIFEs that use async/await instead of chaining .then() callbacks. This will make
the code more consistent with the codebase style and modern TypeScript
practices.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 8af64a5f-393b-4551-aeb9-4135512389f5
📒 Files selected for processing (8)
supabase/functions/_backend/triggers/logsnag_insights.tssupabase/functions/_backend/utils/cloudflare.tssupabase/functions/_backend/utils/logsnag.tssupabase/functions/_backend/utils/tracking.tssupabase/functions/triggers/index.tssupabase/migrations/20260615112920_add_global_stats_completed_shards.sqltests/cloudflare-datetime.unit.test.tstests/logsnag-insights-revenue.unit.test.ts
🔗 Linked repositories identified
CodeRabbit considers these linked repositories for cross-repo context during reviews:
Cap-go/capacitor-updater(manual)
649d4c9 to
5c4c8a5
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5c4c8a5c71
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
5c4c8a5 to
ee6af81
Compare
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
supabase/functions/_backend/triggers/logsnag_insights.ts (1)
1284-1358: 🧹 Nitpick | 🔵 Trivial | 💤 Low valueUse camelCase for local variable names.
Several destructured variables use snake_case instead of camelCase:
updates_external,paying_orgs_for_conversion,need_upgrade. While the usage shard (lines 1446-1462) was updated to use camelCase, this section still has snake_case locals.As per coding guidelines, TypeScript/JavaScript variable names should use camelCase.
♻️ Suggested variable name changes
const [ apps, updates, - updates_external, + updatesExternal, users, orgs, stars, customers, - paying_orgs_for_conversion, + payingOrgsForConversion, onboarded, - need_upgrade, + needUpgrade, plans, actives, ] = await Promise.all([Then update references:
-const not_paying = users - customers.total - plans.Trial -const org_conversion_rate = calculateConversionRate(paying_orgs_for_conversion, orgs) +const notPaying = users - customers.total - plans.Trial +const orgConversionRate = calculateConversionRate(payingOrgsForConversion, orgs)🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@supabase/functions/_backend/triggers/logsnag_insights.ts` around lines 1284 - 1358, Rename the destructured local variables in the Promise.all() destructuring block from snake_case to camelCase to follow TypeScript/JavaScript coding conventions. Change updates_external to updatesExternal, paying_orgs_for_conversion to payingOrgsForConversion, and need_upgrade to needUpgrade. Then search the entire file and update all references to these variables to use the new camelCase names, particularly in the usage section mentioned in the comment that already uses camelCase (around lines 1446-1462).Source: Coding guidelines
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@supabase/functions/_backend/triggers/logsnag_insights.ts`:
- Around line 1284-1358: Rename the destructured local variables in the
Promise.all() destructuring block from snake_case to camelCase to follow
TypeScript/JavaScript coding conventions. Change updates_external to
updatesExternal, paying_orgs_for_conversion to payingOrgsForConversion, and
need_upgrade to needUpgrade. Then search the entire file and update all
references to these variables to use the new camelCase names, particularly in
the usage section mentioned in the comment that already uses camelCase (around
lines 1446-1462).
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 133fc1ea-afd0-4be8-b84e-1acdd1dc1a4c
📒 Files selected for processing (9)
cloudflare_workers/api/index.tssupabase/functions/_backend/triggers/logsnag_insights.tssupabase/functions/_backend/utils/cloudflare.tssupabase/functions/_backend/utils/logsnag.tssupabase/functions/_backend/utils/tracking.tssupabase/functions/triggers/index.tssupabase/migrations/20260615112920_add_global_stats_completed_shards.sqltests/cloudflare-datetime.unit.test.tstests/logsnag-insights-revenue.unit.test.ts
🔗 Linked repositories identified
CodeRabbit considers these linked repositories for cross-repo context during reviews:
Cap-go/capacitor-updater(manual)
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ee6af81c6e
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| stars: getGithubStars(), | ||
| customers: supabase.rpc('get_customer_counts').single().then((res) => { | ||
| getGithubStars(), | ||
| supabase.rpc('get_customer_counts').single().then((res) => { |
There was a problem hiding this comment.
Anchor billing counts to the snapshot date
When a dispatcher retry or manual replay preserves an older date_id, this core shard still reads current billing state: get_customer_counts() filters current stripe_info.status = 'succeeded', and count_all_plans_v2() below also uses current status/NOW() for trials. If subscriptions churn or trials expire after the snapshot day, the retry writes today's paying/monthly/yearly/plan counts into the historical global_stats row, while other shards are now snapshot-bounded, so notifications can report a mixed-date daily snapshot.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 28604a4043
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| date_id: snapshotDateId, | ||
| actives, | ||
| ] = await Promise.all([ | ||
| countAllApps(c), |
There was a problem hiding this comment.
Anchor core totals to the snapshot date
When a dispatcher retry or manual replay preserves an older date_id, these core counters still read current production state and then write it into window.prevDayDateId. If apps, updates, users, or orgs changed after the snapshot day, the retry overwrites the historical global_stats row with today's totals while the rest of the shard is date-bound; use the snapshot end time for these totals or skip rewriting them on dated replays.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a8ddf18248
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| getBundleStorageGb(c), | ||
| successRatePromise, |
There was a problem hiding this comment.
Anchor usage current metrics to the snapshot
When a usage shard for a preserved date_id is replayed late, these calls still read current state: getBundleStorageGb() invokes the current total_bundle_storage_bytes() RPC and getUpdateStats(c) uses the current short now() window in the Cloudflare path (or the current Supabase RPC). The results are then written into window.prevDayDateId, so a queue backlog or manual replay can overwrite a historical snapshot's bundle_storage_gb and success_rate with today's values; pass snapshot bounds or skip rewriting these current-only fields on dated replays.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 14dd3d8b18
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| .then(res => res.count ?? 0), | ||
| getGithubStars(), | ||
| getBillingSnapshotCounts(c, window.prevDayEnd), | ||
| supabase.rpc('count_all_onboarded').single().then((res) => { |
There was a problem hiding this comment.
Bound core RPC metrics during dated replays
When a dispatcher retry or manual replay preserves an older date_id, this still calls count_all_onboarded() (and the adjacent count_all_need_upgrade()), which read current public.apps/stripe_info without any snapshot bound in supabase/schemas/prod.sql. The shard then writes those values into window.prevDayDateId, so apps or plan states changed after that day produce mixed-date onboarded/need_upgrade metrics even though the surrounding totals are now snapshot-bounded. Fresh evidence: this patch bounded the core totals, but these two RPCs remain current-state.
Useful? React with 👍 / 👎.
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 788271a5d2
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const last30daysStart = new Date(prevDayEnd.getTime() - 30 * 24 * 60 * 60 * 1000).toISOString() | ||
| const last30daysEnd = prevDayEnd.toISOString() |
There was a problem hiding this comment.
Bound all build counters to the snapshot end
When a builds shard is replayed for an older date_id, this new snapshot end is only applied to the three last_month queries; the adjacent all-time build_logs and build_requests counts still have no < prevDayEnd bound. If newer builds are created before a delayed retry/manual replay, builds_total, platform totals, and builds_success_* are written into the historical global_stats row with today's totals while the rolling fields are snapshot-bounded.
Useful? React with 👍 / 👎.



Summary (AI generated)
logsnag_insightsglobal stats work out of one monolithic request and into independentadmin_statsshard messages.logsnag_insights_core,logsnag_insights_usage, andlogsnag_insights_revenue.core,usage,revenue,plugins,builds,retention,paid_products,ltv, and delayednotifications.completed_shards, including notification completion, so retries do not skip notification delivery or resend completed snapshots.orgscount and use snapshot-bounded revenue, active-app, usage, device, plugin, and build windows for replayed dates.202, cancelling it only after durable shard queueing, and propagating retry-cancel failures.Motivation (AI generated)
Cloudflare logs showed
/triggers/logsnag_insightsswitching from200 okto0 canceledaround the queue HTTP timeout. The slow work was the full global stats snapshot refresh inside one LogSnag-named trigger. Splitting the queue into separate HTTP shard calls lets Cloudflare retry only the failed metric group and avoids relying on one long Worker invocation.Business Impact (AI generated)
Restores Capgo admin/global metrics freshness without increasing queue timeouts. Daily snapshots can make partial progress, recover from one slow metric group, and avoid sending LogSnag/tracking events with incomplete, stale, or mixed-date values.
Test Plan (AI generated)
bun test tests/cloudflare-datetime.unit.test.ts tests/logsnag-insights-revenue.unit.test.tsbun lint(passes with existing unrelated JSDoc warning insrc/services/compatibilityEvents.ts)bun lint:backendbun run cli:typecheckbun run typecheck:backendbun run typecheck:frontendbash scripts/check-supabase-migration-order.shgit diff --checkbun run cli:typecheck && bun run typecheck:backend && bun run typecheck:frontendGenerated with AI
Summary by CodeRabbit