Repository navigation
feat(integrations): Google Cloud metrics and resource poller - #1333
JeremyFunk wants to merge 38 commits into
Confidence 5/10 · 2 issues to address
🟡 Confidence 5/10 · needs attention
Every hunk of the 13 files read; the risky parts are a per-instance DB write loop and a resource-name join between two Cloud Asset listings.
quality 74/100 · 2 warnings · 3 notes · tests covered · risk medium · 4/4 new units observable
Stacks Cloud SQL health and Query Insights metrics, a per-statement top-25 rank, and each instance's settings synced into the new gcp_resources.details. Safe to merge once the settings write stops being one statement per instance; the open IntegrationsUpstreamError issue is untouched, the poller failing with its own GcpApiError/GcpMetricsIngestError tags that are caught and recorded on the connector.
gcpSqlSettingsreads version, tier, size, HA, Query Insights and max connections off the instance's Cloud Asset datasyncSqlSettingswrites each instance's settings intogcp_resources.detailson the hourly resource syncreadTopranks each instance's statements by execution time and keeps the top 25 per pollgcpAlignmentMsaligns a top group over the whole poll window, one point per poll
Before merge
- Secret · Add secret
MAPLE_GCP_SERVICE_ACCOUNT_KEYto every environment ·apps/alerting/src/worker.ts:71 - Migration · Check it is safe on production data and with the code still deployed ·
packages/db/drizzle/20261015132248_gcp_metrics_poller/migration.sql - Migration · Check it is safe on production data and with the code still deployed ·
packages/db/drizzle/20261015224512_gcp_resource_details/migration.sql - Manual · The
gcp_resources.detailsmigration (20261015224512_gcp_resource_details) applies in the prd alchemy deploy
Findings
🟠 Warning · F5 · syncSqlSettings issues one UPDATE per Cloud SQL instance
performance · packages/backend/src/services/integrations/GcpMetricsService.ts:331-338
Every Cloud SQL instance in the scope is a separate db.run round trip inside syncResources, which runs under RESOURCE_SYNC_TIMEOUT (30 s) and already pages the whole inventory. In an organization scope with hundreds of instances that many statements can eat the timeout, and the settings write stops part-way with no error surfaced; the resource upsert just above it is one batched statement, so the same shape works here — build the (connectorId, name, details) values from gcpSqlSettings(instances) and write them with one PG.update/onConflictDoUpdate or a single PG.sql.
🔵 Note · F6 · workloadOf is declared and set but the mapping hardcodes the type instead
maintainability · packages/backend/src/services/integrations/gcp/mapping.ts:82-86
GcpMetricGroup.workloadOf (packages/domain/src/gcp-metrics.ts:484) is never read anywhere: the Query Insights rules live as resourceType === "cloudsql_instance_database" → "cloudsql_database" here. A group added with workloadOf would silently be stored under its own resource type, and the field's documented contract is unenforced; read group.workloadOf in gcpResourceAttributes or drop the field.
Still open from earlier reviews
- 🟠 Warning · F2 · An ingest 401/403 is retried every tick with no backoff, unlike billing ·
packages/backend/src/services/integrations/GcpMetricsService.ts:523 - 🔵 Note · F3 ·
gcp_push_service_accountbuilds a namegcpConnectorResourceNamesdoes not ·apps/ingest/src/main.rs:5170 - 🔵 Note · F4 ·
fetch_keyscalls Google's certs URL with no span and no peer ·apps/ingest/src/gcp_push_auth.rs:268
Production impact
Open errors in the changed files
| Issue | Service | Occurrences | File |
|---|---|---|---|
| @maple/http/errors/IntegrationsUpstreamError | alerting | 6 | apps/alerting/src/scheduled.ts |
After this merges, Maple checks whether they stop.
Production traffic of the changed files (last 7 days)
| File | Calls/day | Busiest operations |
|---|---|---|
packages/backend/src/services/integrations/GcpConnectorService.ts |
192 | GcpConnectorService.status 189/day, 0.0% errGcpConnectorService.scripts 3/day, 0.0% err |
packages/backend/src/services/integrations/GcpMetricsService.ts |
147 | GcpMetricsService.pollAll 74/day, 0.0% errGcpMetricsService.pollConnector 73/day, 0.0% err |
Telemetry this change adds and removes (5)
- ➕ attribute
maple.gcp.poll_failed·packages/backend/src/services/integrations/GcpMetricsService.ts:258 - ➕ attribute
gcp.resource.type·packages/backend/src/services/integrations/gcp/mapping.ts:44 - ➕ attribute
cloud.account.id·packages/backend/src/services/integrations/gcp/mapping.ts:48 - ➕ attribute
network.io.direction·packages/domain/src/gcp-metrics.ts:99 - ➕ attribute
disk.io.direction·packages/domain/src/gcp-metrics.ts:101
What was checked
- Query Insights and per-statement metric groups share no (metric, kind) with the rest of the table, pinned by
gcp-metrics.test.ts distributionQuantilebucket indexing for exponential, linear and explicit buckets, pinned bymapping.test.ts- Replica max-connections default takes the primary's memory across pages, pinned by the service test at
GcpMetricsService.test.ts:1463
Observability coverage: 4 of 4 changes observable
| Change | Kind | Observable | Evidence |
|---|---|---|---|
| alerting */5 metrics+inventory tick for GCP connectors | cron consumer | yes | span alerting.gcp_metrics_tick (apps/alerting/src/scheduled.ts:126) with GcpMetricsService.pollAll/pollConnector spans, live at 74 and 73 calls/day |
| Cloud Monitoring timeSeries.list and Cloud Asset searchAllResources/assets.list calls | outbound call | yes | shared call helper sets peer.service "google-cloud" (gcp/api.ts:149); the Cloud SQL listing uses it |
| OTLP upload to the ingest gateway | outbound call | yes | emitMetrics annotates peer.service "ingest" (GcpMetricsService.ts:290) |
| hourly Cloud SQL settings sync | background step | yes | runs inside the connector poll span, its Cloud Asset call carries a client span; outcome lands on lastResourcesError/resourcesSyncedAt |
fca89dd · Updated on every push. Reply "won't fix" to dismiss a finding, or mention @maple-review-bot to ask about one.
Annotations
Check warning on line 338 in packages/backend/src/services/integrations/GcpMetricsService.ts
maple-review-bot / Maple / review
performance: `syncSqlSettings` issues one UPDATE per Cloud SQL instance
Every Cloud SQL instance in the scope is a separate `db.run` round trip inside `syncResources`, which runs under `RESOURCE_SYNC_TIMEOUT` (30 s) and already pages the whole inventory. In an organization scope with hundreds of instances that many statements can eat the timeout, and the settings write stops part-way with no error surfaced; the resource upsert just above it is one batched statement, so the same shape works here — build the `(connectorId, name, details)` values from `gcpSqlSettings(instances)` and write them with one `PG.update`/`onConflictDoUpdate` or a single `PG.sql`.
Check notice on line 86 in packages/backend/src/services/integrations/gcp/mapping.ts
maple-review-bot / Maple / review
maintainability: `workloadOf` is declared and set but the mapping hardcodes the type instead
`GcpMetricGroup.workloadOf` (`packages/domain/src/gcp-metrics.ts:484`) is never read anywhere: the Query Insights rules live as `resourceType === "cloudsql_instance_database"` → `"cloudsql_database"` here. A group added with `workloadOf` would silently be stored under its own resource type, and the field's documented contract is unenforced; read `group.workloadOf` in `gcpResourceAttributes` or drop the field.