Skip to content

Commit 449e4e5

Browse files
authored
Merge pull request #466 from firebase/next
October 8, 2020 Release
2 parents 0b8edc6 + d0c1b55 commit 449e4e5

File tree

8 files changed

+42
-94
lines changed

8 files changed

+42
-94
lines changed

firestore-counter/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## Version 0.2.0
2+
3+
feature - convert Firestore Counter to use scheduled functions (#353)
4+
15
## Version 0.1.5
26

37
feature - Add new Cloud Functions locations. For more information about locations and their pricing tiers, refer to the [location selection guide](https://firebase.google.com/docs/functions/locations).

firestore-counter/POSTINSTALL.md

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
### Post-installation configuration
22

3-
Before you can use this extension, you'll need to update your security rules, set up a Cloud Scheduler job, and add some code to your JavaScript app.
3+
Before you can use this extension, you'll need to update your security rules and add some code to your JavaScript app.
4+
45

56
#### Update security rules
67

@@ -19,22 +20,6 @@ match /databases/{database}/documents/pages/{page} {
1920
```
2021

2122

22-
#### Set up a Cloud Scheduler job
23-
24-
**IMPORTANT:** Note the following about v0.1.1 of this extension:
25-
- **If you updated your extension from v0.1.0 to v0.1.1:** We recommend that you edit your Cloud Scheduler job to instead send a message to the extension's Pub/Sub topic, as described in this section. Although it's not recommended, if you leave your Cloud Scheduler job calling `${function:controller.url}`, your extension will continue to run as expected. For more information about the changes for v0.1.1, refer to the [changelog](https://github.com/firebase/extensions/blob/master/firestore-counter/CHANGELOG.md).
26-
- **If you installed this extension for the first time at v0.1.1 or later:** Follow the instructions as described in this section.
27-
28-
Set up a [Cloud Scheduler job](https://cloud.google.com/scheduler/docs/quickstart) to regularly send a message to the extension's Pub/Sub topic (`${param:EXT_INSTANCE_ID}`). This Pub/Sub topic then automatically triggers the controllerCore function (`${function:controllerCore.name}`). This controllerCore function is created by the extension. It works by either aggregating shards itself or scheduling and monitoring workers to aggregate shards.
29-
30-
As an example, to set up the required Cloud Scheduler job, you can run the following `gcloud` commands:
31-
32-
```
33-
gcloud --project=${param:PROJECT_ID} services enable cloudscheduler.googleapis.com
34-
gcloud --project=${param:PROJECT_ID} scheduler jobs create pubsub ${param:EXT_INSTANCE_ID} --schedule="* * * * *" --topic=${param:EXT_INSTANCE_ID} --message-body="{}"
35-
```
36-
37-
3823
#### Specify a document path and increment value in your web app
3924

4025
1. Download and copy the [compiled client sample](https://github.com/firebase/extensions/blob/master/firestore-counter/clients/web/dist/sharded-counter.js) into your application project.
@@ -75,6 +60,14 @@ gcloud --project=${param:PROJECT_ID} scheduler jobs create pubsub ${param:EXT_IN
7560
</html>
7661
```
7762

63+
64+
#### Upgrading from v0.1.3 and earlier
65+
66+
If you installed v0.1.3 or an earlier version of this extension, you set up a Cloud Scheduler job that either sent messages to the extension's Pub/Sub topic (`${param:EXT_INSTANCE_ID}`) or called the extension's controller function. Starting in v0.1.4, the controllerCore function (`${function:controllerCore.name}`) has a configurable schedule, so the manually-created Cloud Scheduler job is no longer required and will start to fail.
67+
68+
Delete the old Cloud Scheduler job on the [Cloud Scheduler](https://console.cloud.google.com/cloudscheduler?project=_) page of the Cloud console.
69+
70+
7871
### Using the extension
7972

8073
After you complete the post-installation configuration above, the process runs as follows:

firestore-counter/PREINSTALL.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ Before installing this extension, make sure that you've [set up a Cloud Firestor
1818
After installing this extension, you'll need to:
1919

2020
- Update your [database security rules](https://firebase.google.com/docs/rules).
21-
- Set up a [Cloud Scheduler job](https://cloud.google.com/scheduler/docs/quickstart) to regularly call the controllerCore function, which is created by this extension. It works by either aggregating shards itself or scheduling and monitoring workers to aggregate shards.
2221
- Use the provided [client sample](https://github.com/firebase/extensions/blob/master/firestore-counter/clients/web/src/index.ts) or your own client code to specify your document path and increment values.
2322

2423
Detailed information for these post-installation tasks are provided after you install this extension.

firestore-counter/extension.yaml

Lines changed: 19 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,11 @@
1313
# limitations under the License.
1414

1515
name: firestore-counter
16-
version: 0.1.5
16+
version: 0.2.0
1717
specVersion: v1beta
1818

1919
displayName: Distributed Counter
20-
description:
21-
Records event counters at scale to accommodate high-velocity writes to Cloud Firestore.
20+
description: Records event counters at scale to accommodate high-velocity writes to Cloud Firestore.
2221

2322
license: Apache-2.0
2423

@@ -36,48 +35,29 @@ contributors:
3635
- authorName: Invertase
3736
email: oss@invertase.io
3837
url: https://github.com/invertase
39-
4038

4139
billingRequired: true
4240

4341
roles:
4442
- role: datastore.user
45-
reason:
46-
Allows the extension to aggregate Cloud Firestore counter shards.
47-
- role: pubsub.publisher
48-
reason:
49-
Allows the HTTPS controller function to publish a message to the extension's Pub/Sub topic,
50-
which triggers the controllerCore function.
43+
reason: Allows the extension to aggregate Cloud Firestore counter shards.
44+
- role: cloudscheduler.admin
45+
reason: Allows the extension to create a new Cloud Scheduler function.
5146

5247
resources:
5348
- name: controllerCore
5449
type: firebaseextensions.v1beta.function
55-
description:
56-
Scheduled to run every minute.
57-
This function either aggregates shards itself, or it schedules and monitors workers to aggregate shards.
50+
description: This scheduled function either aggregates shards itself, or it schedules and monitors workers to aggregate shards.
5851
properties:
5952
location: ${LOCATION}
6053
runtime: nodejs10
6154
maxInstances: 1
62-
eventTrigger:
63-
eventType: google.pubsub.topic.publish
64-
resource: projects/${PROJECT_ID}/topics/${EXT_INSTANCE_ID}
65-
66-
- name: controller
67-
type: firebaseextensions.v1beta.function
68-
description:
69-
Maintained for backwards compatibility.
70-
This function relays a message to the extension's Pub/Sub topic to trigger the controllerCore function.
71-
properties:
72-
location: ${LOCATION}
73-
runtime: nodejs10
74-
maxInstances: 1
75-
httpsTrigger: {}
55+
scheduleTrigger:
56+
schedule: "every ${SCHEDULE_FREQUENCY} minutes"
7657

7758
- name: onWrite
7859
type: firebaseextensions.v1beta.function
79-
description:
80-
Listens for changes on counter shards that may need aggregating. This function is limited to max 1 instance.
60+
description: Listens for changes on counter shards that may need aggregating. This function is limited to max 1 instance.
8161
properties:
8262
location: ${LOCATION}
8363
runtime: nodejs10
@@ -89,8 +69,7 @@ resources:
8969

9070
- name: worker
9171
type: firebaseextensions.v1beta.function
92-
description:
93-
Monitors a range of shards and aggregates them, as needed.
72+
description: Monitors a range of shards and aggregates them, as needed.
9473
There may be 0 or more worker functions running at any point in time.
9574
The controllerCore function is responsible for scheduling and monitoring these workers.
9675
properties:
@@ -163,3 +142,12 @@ params:
163142
for example, `my_collection/doc` or `my_collection/doc/subcollection/doc`, but not `my_collection`.
164143
default: _firebase_ext_/sharded_counter
165144
required: true
145+
146+
- param: SCHEDULE_FREQUENCY
147+
label: Frequency for controllerCore function to be run
148+
description: >-
149+
In minutes, how often should the function to aggregate shards be run?
150+
validationRegex: "^[1-9][0-9]*$"
151+
validationErrorMessage: The number of minutes must be an integer value greater than zero.
152+
default: "1"
153+
required: true

firestore-counter/functions/README.md

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ Before installing this extension, make sure that you've [set up a Cloud Firestor
2626
After installing this extension, you'll need to:
2727

2828
- Update your [database security rules](https://firebase.google.com/docs/rules).
29-
- Set up a [Cloud Scheduler job](https://cloud.google.com/scheduler/docs/quickstart) to regularly call the controllerCore function, which is created by this extension. It works by either aggregating shards itself or scheduling and monitoring workers to aggregate shards.
3029
- Use the provided [client sample](https://github.com/firebase/extensions/blob/master/firestore-counter/clients/web/src/index.ts) or your own client code to specify your document path and increment values.
3130

3231
Detailed information for these post-installation tasks are provided after you install this extension.
@@ -49,13 +48,13 @@ To install an extension, your project must be on the [Blaze (pay as you go) plan
4948

5049
* Document path for internal state: What is the path to the document where the extension can keep its internal state?
5150

51+
* Frequency for controllerCore function to be run: In minutes, how often should the function to aggregate shards be run?
5252

5353

54-
**Cloud Functions:**
5554

56-
* **controllerCore:** Scheduled to run every minute. This function either aggregates shards itself, or it schedules and monitors workers to aggregate shards.
55+
**Cloud Functions:**
5756

58-
* **controller:** Maintained for backwards compatibility. This function relays a message to the extension's Pub/Sub topic to trigger the controllerCore function.
57+
* **controllerCore:** This scheduled function either aggregates shards itself, or it schedules and monitors workers to aggregate shards.
5958

6059
* **onWrite:** Listens for changes on counter shards that may need aggregating. This function is limited to max 1 instance.
6160

@@ -71,4 +70,4 @@ This extension will operate with the following project IAM roles:
7170

7271
* datastore.user (Reason: Allows the extension to aggregate Cloud Firestore counter shards.)
7372

74-
* pubsub.publisher (Reason: Allows the HTTPS controller function to publish a message to the extension's Pub/Sub topic, which triggers the controllerCore function.)
73+
* cloudscheduler.admin (Reason: Allows the extension to create a new Cloud Scheduler function.)

firestore-counter/functions/lib/index.js

Lines changed: 3 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,24 +15,21 @@
1515
* limitations under the License.
1616
*/
1717
Object.defineProperty(exports, "__esModule", { value: true });
18-
exports.onWrite = exports.worker = exports.controller = exports.controllerCore = void 0;
18+
exports.onWrite = exports.worker = exports.controllerCore = void 0;
1919
const functions = require("firebase-functions");
2020
const admin = require("firebase-admin");
21-
const pubsub_1 = require("@google-cloud/pubsub");
2221
const worker_1 = require("./worker");
2322
const controller_1 = require("./controller");
2423
admin.initializeApp();
2524
const firestore = admin.firestore();
2625
firestore.settings({ timestampsInSnapshots: true });
27-
let pubsub;
2826
const SHARDS_COLLECTION_ID = "_counter_shards_";
29-
const WORKERS_COLLECTION_ID = "_counter_workers_";
3027
/**
31-
* The controllerCore is scheduled every minute. It tries to aggregate shards if
28+
* The controllerCore is scheduled to run automatically. It tries to aggregate shards if
3229
* there's less than 200 of them. Otherwise it is scheduling and monitoring
3330
* workers to do the aggregation.
3431
*/
35-
exports.controllerCore = functions.handler.pubsub.topic.onPublish(async () => {
32+
exports.controllerCore = functions.handler.pubsub.schedule.onRun(async () => {
3633
const metadocRef = firestore.doc(process.env.INTERNAL_STATE_PATH);
3734
const controller = new controller_1.ShardedCounterController(metadocRef, SHARDS_COLLECTION_ID);
3835
let status = await controller.aggregateOnce({ start: "", end: "" }, 200);
@@ -43,18 +40,6 @@ exports.controllerCore = functions.handler.pubsub.topic.onPublish(async () => {
4340
}
4441
return null;
4542
});
46-
/**
47-
* Backwards compatible HTTPS function
48-
*/
49-
exports.controller = functions.handler.https.onRequest(async (req, res) => {
50-
if (!pubsub) {
51-
pubsub = new pubsub_1.PubSub();
52-
}
53-
await pubsub
54-
.topic(process.env.EXT_INSTANCE_ID)
55-
.publish(Buffer.from(JSON.stringify({})));
56-
res.status(200).send("Ok");
57-
});
5843
/**
5944
* Worker is responsible for aggregation of a defined range of shards. It is controlled
6045
* by a worker metadata document. At the end of its run (that lasts for 45s) it writes

firestore-counter/functions/package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
"license": "Apache-2.0",
66
"description": "Auto-scalable counters for your app.",
77
"dependencies": {
8-
"@google-cloud/pubsub": "^1.1.5",
98
"deep-equal": "^1.0.1",
109
"firebase-admin": "^8.3.0",
1110
"firebase-functions": "^3.9.0",

firestore-counter/functions/src/index.ts

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -16,25 +16,21 @@
1616

1717
import * as functions from "firebase-functions";
1818
import * as admin from "firebase-admin";
19-
import { PubSub } from "@google-cloud/pubsub";
2019
import { ShardedCounterWorker } from "./worker";
2120
import { ShardedCounterController, ControllerStatus } from "./controller";
2221

2322
admin.initializeApp();
2423
const firestore = admin.firestore();
2524
firestore.settings({ timestampsInSnapshots: true });
2625

27-
let pubsub;
28-
2926
const SHARDS_COLLECTION_ID = "_counter_shards_";
30-
const WORKERS_COLLECTION_ID = "_counter_workers_";
3127

3228
/**
33-
* The controllerCore is scheduled every minute. It tries to aggregate shards if
29+
* The controllerCore is scheduled to run automatically. It tries to aggregate shards if
3430
* there's less than 200 of them. Otherwise it is scheduling and monitoring
3531
* workers to do the aggregation.
3632
*/
37-
export const controllerCore = functions.handler.pubsub.topic.onPublish(
33+
export const controllerCore = functions.handler.pubsub.schedule.onRun(
3834
async () => {
3935
const metadocRef = firestore.doc(process.env.INTERNAL_STATE_PATH);
4036
const controller = new ShardedCounterController(
@@ -53,21 +49,6 @@ export const controllerCore = functions.handler.pubsub.topic.onPublish(
5349
}
5450
);
5551

56-
/**
57-
* Backwards compatible HTTPS function
58-
*/
59-
export const controller = functions.handler.https.onRequest(
60-
async (req, res) => {
61-
if (!pubsub) {
62-
pubsub = new PubSub();
63-
}
64-
await pubsub
65-
.topic(process.env.EXT_INSTANCE_ID)
66-
.publish(Buffer.from(JSON.stringify({})));
67-
res.status(200).send("Ok");
68-
}
69-
);
70-
7152
/**
7253
* Worker is responsible for aggregation of a defined range of shards. It is controlled
7354
* by a worker metadata document. At the end of its run (that lasts for 45s) it writes

0 commit comments

Comments
 (0)