Skip to content

[firestore-bigquery-change-tracker] initializeLatestMaterializedView drops maxStaleness and refreshIntervalMinutes on the incremental path #3213

Description

@CorieW

Package: @firebaseextensions/firestore-bigquery-change-tracker, src/bigquery/initializeLatestMaterializedView.ts on next.

With VIEW_TYPE=materialized_incremental, both REFRESH_INTERVAL_MINUTES and MAX_STALENESS are silently ignored. The incremental branch does not forward them to the query builder, while the non-incremental branch does:

const { query, source } = config.useIncrementalMaterializedView
  ? buildMaterializedViewQuery({
      projectId: bq.projectId,
      datasetId: config.datasetId,
      tableName: rawChangeLogTableName,
      rawLatestViewName,
      schema,
      // maxStaleness and refreshIntervalMinutes are never passed
    })
  : buildNonIncrementalMaterializedViewQuery({
      ...
      maxStaleness: config.maxStaleness,
      refreshIntervalMinutes: config.refreshIntervalMinutes,
      enableRefresh: true,
      ...
    });

buildMaterializedViewQuery accepts both and is written to emit them (src/bigquery/snapshot.ts), but receives undefined for each, so its options array stays empty and optionsString collapses to "". The emitted DDL therefore carries no OPTIONS clause at all and BigQuery applies its own defaults (refresh_interval_minutes = 30, enable_refresh = true).

Reproduction

Deployed live to a test project with VIEW_TYPE=materialized_incremental and REFRESH_INTERVAL_MINUTES=60, as both the extension and the kit:

refreshIntervalMs expected
firebase/firestore-bigquery-export@0.3.3 1800000 3600000
@firebase-function-kits/firestore-bigquery-export@0.0.2-rc.14 1800000 3600000

REFRESH_INTERVAL_MINUTES=60 was confirmed present on the deployed resources themselves (the Cloud Run container env of the task that builds the DDL, and the Extensions API record of the installed instance), so neither is falling back to the param default.

The DDL logged by the task confirms no options are emitted:

CREATE MATERIALIZED VIEW `<project>.<dataset>.<table>_raw_latest` AS (

BigQuery's reconstructed DDL from INFORMATION_SCHEMA.TABLES agrees, and contrasts with a non-incremental instance configured with MAX_STALENESS, which does get an OPTIONS( clause.

Secondary effect

shouldRecreateMaterializedView decides whether to recreate by comparing formatted query text plus the incremental/non-incremental flag. Because these options never reach the query text, changing REFRESH_INTERVAL_MINUTES or MAX_STALENESS on an existing incremental view produces a byte-identical query and the view is left alone with Materialized view requested, but a view with matching configuration exists. Skipping creation. So the values cannot be corrected by reconfiguring either; the view has to be dropped manually.

Fix

Pass both arguments in the incremental branch. Note the non-incremental branch also passes enableRefresh: true explicitly while the incremental branch sets nothing — today both land on true because that is BigQuery's default, so a fix that adds only refresh_interval_minutes would leave that asymmetry in place.

Worth a test asserting the generated DDL contains refresh_interval_minutes and max_staleness for the incremental path, since the current tests only cover the non-incremental one.

This is pre-existing extension behaviour, not a kit-migration regression; the kit inherits it via the shared tracker dependency (the extension's ^2.0.4 and the kit's ^2.2.1 both resolve to 2.2.1, and the bug is present in the 2.0.4 source too).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions