Skip to content

feat(integrations): Google Cloud metrics and resource poller - #1333

Open
JeremyFunk wants to merge 38 commits into
feat/gcp-log-push-ingestfrom
feat/gcp-metrics-poller
Open

JeremyFunk wants to merge 38 commits into
feat/gcp-log-push-ingestfrom
feat/gcp-metrics-poller

feat(gcp): poll Cloud SQL health, Query Insights and instance settings

fca89dd
Select commit
Loading
Failed to load commit list.
Maple Review Bot / Maple / review completed Oct 15, 2026 in 3m 0s

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.

  • gcpSqlSettings reads version, tier, size, HA, Query Insights and max connections off the instance's Cloud Asset data
  • syncSqlSettings writes each instance's settings into gcp_resources.details on the hourly resource sync
  • readTop ranks each instance's statements by execution time and keeps the top 25 per poll
  • gcpAlignmentMs aligns a top group over the whole poll window, one point per poll

Before merge

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

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% err
GcpConnectorService.scripts 3/day, 0.0% err
packages/backend/src/services/integrations/GcpMetricsService.ts 147 GcpMetricsService.pollAll 74/day, 0.0% err
GcpMetricsService.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
  • distributionQuantile bucket indexing for exponential, linear and explicit buckets, pinned by mapping.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

See this annotation in the file changed.

@maple-review-bot 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

See this annotation in the file changed.

@maple-review-bot 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.