Skip to content

Commit

Permalink
fslogical: Initial support for Firestore
Browse files Browse the repository at this point in the history
This change adds initial support for importing document collections from Google
Cloud Firestore. The new dialect operates in a key-pagination mode for initial
backfills and then switches to a streaming mode once it has caught up.

The implementation has several caveats:
* All documents to be synched must have an updated_at field (the name is
  configurable) which is set to the server-provided timestamp. These document
  timestamps are used to establish a consistent-point barrier that separates
  backfills from streaming operations.
* Document deletions that occur outside of streaming mode may be lost. There
  does not appear to be a service in Firestore which is analogous to a
  transaction log or CDC feed.

Testing uses a custom container image, uploaded to the GitHub package repo,
that contains a local firestore emulator. We do not depend on production
Firestore. The emulator image is built and deployed by a new workflow.
  • Loading branch information
bobvawter committed Aug 9, 2022
1 parent 1c844ee commit 55b8169
Show file tree
Hide file tree
Showing 20 changed files with 1,520 additions and 10 deletions.
7 changes: 6 additions & 1 deletion .github/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,18 @@ services:
image: cockroachdb/cockroach:latest-v22.1
network_mode: host
command: start-single-node --insecure --store type=mem,size=2G
firestore:
image: ghcr.io/cockroachdb/cdc-sink/firestore-emulator:latest
# Expose the emulator on port 8181 to avoid conflict with CRDB admin UI.
ports:
- "8181:8080"
mysql-v8:
image: mysql:8-debian
platform: linux/x86_64
environment:
MYSQL_ROOT_PASSWORD: SoupOrSecret
MYSQL_DATABASE: _cdc_sink
command:
command:
--default-authentication-plugin=mysql_native_password
--gtid-mode=on
--enforce-gtid-consistency=on
Expand Down
9 changes: 9 additions & 0 deletions .github/firestore/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Build from a Node base, add the required JDK, then install.
# https://firebase.google.com/docs/emulator-suite/install_and_configure
FROM node:alpine
RUN apk add openjdk11
RUN npm install -g firebase-tools
# Pre-cache the firestore emulator.
RUN firebase setup:emulators:firestore
COPY emulators.json .
CMD ["firebase", "emulators:start", "--only", "firestore", "-c", "emulators.json"]
3 changes: 3 additions & 0 deletions .github/firestore/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
This directory builds a container which runs the Google Cloud Firestore emulator. We save time in
each of the tests by pre-caching the jar files which the firebase cli will download. We also
configure the emulator to bind to all addresses instead of loopback.
7 changes: 7 additions & 0 deletions .github/firestore/emulators.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"emulators": {
"firestore": {
"host": "0.0.0.0"
}
}
}
48 changes: 48 additions & 0 deletions .github/workflows/firestore.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Build the Firestore emulator docker image and push it to the GitHub
# package repository.
name: Firestore Emulator
permissions:
contents: read
packages: write
on:
push:
branches: [ master ]
paths:
- ".github/firestore/**"
pull_request:
paths:
- ".github/firestore/**"

env:
REGISTRY: ghcr.io
IMAGE_NAME: ghcr.io/${{ github.repository }}/firestore-emulator

jobs:
# https://docs.github.com/en/actions/publishing-packages/publishing-docker-images#publishing-images-to-github-packages
push:
name: Push Firestore Emulator to GH Packages
runs-on: ubuntu-latest
steps:
- name: Check out the repo
uses: actions/checkout@v3

- name: Log in to GitHub Package Registry
uses: docker/login-action@v2
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v4
with:
images: ${{ env.IMAGE_NAME }}

- name: Build and push Docker image
uses: docker/build-push-action@v3
with:
context: ./.github/firestore
push: true
tags: ${{ env.IMAGE_NAME }}:latest
labels: ${{ steps.meta.outputs.labels }}
2 changes: 2 additions & 0 deletions .github/workflows/golang.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ jobs:
# directory.
cockroachdb: [ v22.1 ]
integration:
- "firestore"
- "mysql-v8"
- "mysql-mariadb-v10"
- "postgresql-v11"
Expand All @@ -155,6 +156,7 @@ jobs:
- cockroachdb: v21.2
env:
COVER_OUT: coverage-${{ matrix.cockroachdb }}-${{ matrix.integration }}.out
FIRESTORE_EMULATOR_HOST: 127.0.0.1:8181
JUNIT_OUT: junit-${{ matrix.cockroachdb }}-${{ matrix.integration }}.xml
TEST_OUT: go-test-${{ matrix.cockroachdb }}-${{ matrix.integration }}.json
steps:
Expand Down
19 changes: 15 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module github.com/cockroachdb/cdc-sink
go 1.17

require (
cloud.google.com/go/firestore v1.6.1
github.com/cockroachdb/apd v1.1.0
github.com/cockroachdb/crlfmt v0.0.0-20210128092314-b3eff0b87c79
github.com/go-mysql-org/go-mysql v1.6.0
Expand All @@ -25,21 +26,27 @@ require (
github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.8.0
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616
golang.org/x/net v0.0.0-20220225172249-27dd8689420f
golang.org/x/net v0.0.0-20220722155237-a158d28d115b
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f
golang.org/x/tools v0.1.11-0.20220513221640-090b14e8501f
google.golang.org/api v0.88.0
honnef.co/go/tools v0.3.3
)

require (
cloud.google.com/go v0.103.0 // indirect
cloud.google.com/go/compute v1.7.0 // indirect
github.com/BurntSushi/toml v0.4.1 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/cockroachdb/gostdlib v1.13.0 // indirect
github.com/cockroachdb/ttycolor v0.0.0-20180709150743-a1d5aaeb377d // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/go-cmp v0.5.8 // indirect
github.com/google/subcommands v1.0.1 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.1.0 // indirect
github.com/googleapis/gax-go/v2 v2.4.0 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/jackc/chunkreader/v2 v2.0.1 // indirect
github.com/jackc/pgio v1.0.0 // indirect
Expand All @@ -55,14 +62,18 @@ require (
github.com/shopspring/decimal v1.2.0 // indirect
github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726 // indirect
github.com/siddontang/go-log v0.0.0-20180807004314-8d05993dda07 // indirect
go.opencensus.io v0.23.0 // indirect
go.uber.org/atomic v1.7.0 // indirect
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa // indirect
golang.org/x/exp/typeparams v0.0.0-20220218215828-6cf2b201936e // indirect
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect
golang.org/x/oauth2 v0.0.0-20220722155238-128564f6959c // indirect
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa // indirect
golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20220722212130-b98a9ff5e252 // indirect
google.golang.org/grpc v1.48.0 // indirect
google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
Loading

0 comments on commit 55b8169

Please sign in to comment.