From 96f085f3df7c8e6e20dbffb14ebf6ebb533fc036 Mon Sep 17 00:00:00 2001 From: Yoshi Automation Bot Date: Fri, 3 Jan 2020 09:08:54 -0800 Subject: [PATCH] fix: retry writes that fail with status code ABORTED (#854) --- .nycrc | 1 + README.md | 4 +- dev/protos/protos.json | 14 +- dev/src/v1/firestore_admin_client.ts | 8 +- dev/src/v1/firestore_client.ts | 26 ++-- dev/src/v1/firestore_client_config.json | 21 +-- dev/src/v1beta1/firestore_client.ts | 6 +- dev/synth.metadata | 193 ++++++++++++------------ dev/test/index.ts | 2 +- 9 files changed, 134 insertions(+), 141 deletions(-) diff --git a/.nycrc b/.nycrc index 367688844..b18d5472b 100644 --- a/.nycrc +++ b/.nycrc @@ -12,6 +12,7 @@ "**/scripts", "**/protos", "**/test", + "**/*.d.ts", ".jsdoc.js", "**/.jsdoc.js", "karma.conf.js", diff --git a/README.md b/README.md index 536072cc8..d1cd97732 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,9 @@ This is the Node.js Server SDK for [Google Cloud Firestore](https://firebase.goo This Cloud Firestore Server SDK uses Google’s Cloud Identity and Access Management for authentication and should only be used in trusted environments. Your Cloud Identity credentials allow you bypass all access restrictions and provide read and write access to all data in your Cloud Firestore project. -Applications that use Google's Server SDKs should not be used in end-user environments, such as on phones or on publicly hosted websites. If you are developing a Web or Node.js application that accesses Cloud Firestore on behalf of end users, use the Firebase Client SDK. +The Cloud Firestore Server SDKs are designed to manage the full set of data in your Cloud Firestore project and work best with reliable network connectivity. Data operations performed via these SDKs directly access the Cloud Firestore backend and all document reads and writes are optimized for high throughput. + +Applications that use Google's Server SDKs should not be used in end-user environments, such as on phones or on publicly hosted websites. If you are developing a Web or Node.js application that accesses Cloud Firestore on behalf of end users, use the firebase Client SDK. **Note:** This Cloud Firestore Server SDK does not support Firestore databases created in [Datastore mode](https://cloud.google.com/datastore/docs/firestore-or-datastore#in_datastore_mode). To access these databases, use the [Datastore SDK](https://www.npmjs.com/package/@google-cloud/datastore). diff --git a/dev/protos/protos.json b/dev/protos/protos.json index e0eff68d2..43a9cfaad 100644 --- a/dev/protos/protos.json +++ b/dev/protos/protos.json @@ -1139,13 +1139,6 @@ } } }, - "Direction": { - "values": { - "DIRECTION_UNSPECIFIED": 0, - "ASCENDING": 1, - "DESCENDING": 2 - } - }, "FieldReference": { "fields": { "fieldPath": { @@ -1162,6 +1155,13 @@ "id": 2 } } + }, + "Direction": { + "values": { + "DIRECTION_UNSPECIFIED": 0, + "ASCENDING": 1, + "DESCENDING": 2 + } } } }, diff --git a/dev/src/v1/firestore_admin_client.ts b/dev/src/v1/firestore_admin_client.ts index ba1680b26..57e3ec599 100644 --- a/dev/src/v1/firestore_admin_client.ts +++ b/dev/src/v1/firestore_admin_client.ts @@ -278,6 +278,9 @@ export class FirestoreAdminClient { for (const methodName of firestoreAdminStubMethods) { const innerCallPromise = this.firestoreAdminStub.then( stub => (...args: Array<{}>) => { + if (this._terminated) { + return Promise.reject('The client has already been closed.'); + } return stub[methodName].apply(stub, args); }, (err: Error | null | undefined) => () => { @@ -298,9 +301,6 @@ export class FirestoreAdminClient { callOptions?: CallOptions, callback?: APICallback ) => { - if (this._terminated) { - return Promise.reject('The client has already been closed.'); - } return apiCall(argument, callOptions, callback); }; } @@ -1270,7 +1270,7 @@ export class FirestoreAdminClient { * @param {string} collection * @returns {string} Resource name string. */ - collectiongroupPath(project: string, database: string, collection: string) { + collectionGroupPath(project: string, database: string, collection: string) { return this._pathTemplates.collectiongroupPathTemplate.render({ project, database, diff --git a/dev/src/v1/firestore_client.ts b/dev/src/v1/firestore_client.ts index 8bcf8b6ad..86cd60bd0 100644 --- a/dev/src/v1/firestore_client.ts +++ b/dev/src/v1/firestore_client.ts @@ -37,20 +37,12 @@ const version = require('../../../package.json').version; /** * The Cloud Firestore service. * - * This service exposes several types of comparable timestamps: - * - * * `create_time` - The time at which a document was created. Changes only - * when a document is deleted, then re-created. Increases in a strict - * monotonic fashion. - * * `update_time` - The time at which a document was last updated. Changes - * every time a document is modified. Does not change when a write results - * in no modifications. Increases in a strict monotonic fashion. - * * `read_time` - The time at which a particular state was observed. Used - * to denote a consistent snapshot of the database or the time at which a - * Document was observed to not exist. - * * `commit_time` - The time at which the writes in a transaction were - * committed. Any read with an equal or greater `read_time` is guaranteed - * to see the effects of the transaction. + * Cloud Firestore is a fast, fully managed, serverless, cloud-native NoSQL + * document database that simplifies storing, syncing, and querying data for + * your mobile, web, and IoT apps at global scale. Its client libraries provide + * live synchronization and offline support, while its security features and + * integrations with Firebase and Google Cloud Platform (GCP) accelerate + * building truly serverless apps. * @class * @memberof v1 */ @@ -225,6 +217,9 @@ export class FirestoreClient { for (const methodName of firestoreStubMethods) { const innerCallPromise = this.firestoreStub.then( stub => (...args: Array<{}>) => { + if (this._terminated) { + return Promise.reject('The client has already been closed.'); + } return stub[methodName].apply(stub, args); }, (err: Error | null | undefined) => () => { @@ -245,9 +240,6 @@ export class FirestoreClient { callOptions?: CallOptions, callback?: APICallback ) => { - if (this._terminated) { - return Promise.reject('The client has already been closed.'); - } return apiCall(argument, callOptions, callback); }; } diff --git a/dev/src/v1/firestore_client_config.json b/dev/src/v1/firestore_client_config.json index b1e32f327..60230c0d7 100644 --- a/dev/src/v1/firestore_client_config.json +++ b/dev/src/v1/firestore_client_config.json @@ -7,8 +7,9 @@ "DEADLINE_EXCEEDED", "UNAVAILABLE" ], - "deadline_exceeded_internal_unavailable": [ + "deadline_exceeded_aborted_internal_unavailable": [ "DEADLINE_EXCEEDED", + "ABORTED", "INTERNAL", "UNAVAILABLE" ] @@ -27,12 +28,12 @@ "methods": { "GetDocument": { "timeout_millis": 60000, - "retry_codes_name": "deadline_exceeded_internal_unavailable", + "retry_codes_name": "deadline_exceeded_aborted_internal_unavailable", "retry_params_name": "default" }, "ListDocuments": { "timeout_millis": 60000, - "retry_codes_name": "deadline_exceeded_internal_unavailable", + "retry_codes_name": "deadline_exceeded_aborted_internal_unavailable", "retry_params_name": "default" }, "CreateDocument": { @@ -47,17 +48,17 @@ }, "DeleteDocument": { "timeout_millis": 60000, - "retry_codes_name": "deadline_exceeded_internal_unavailable", + "retry_codes_name": "deadline_exceeded_aborted_internal_unavailable", "retry_params_name": "default" }, "BatchGetDocuments": { "timeout_millis": 300000, - "retry_codes_name": "deadline_exceeded_internal_unavailable", + "retry_codes_name": "deadline_exceeded_aborted_internal_unavailable", "retry_params_name": "default" }, "BeginTransaction": { "timeout_millis": 60000, - "retry_codes_name": "deadline_exceeded_internal_unavailable", + "retry_codes_name": "deadline_exceeded_aborted_internal_unavailable", "retry_params_name": "default" }, "Commit": { @@ -67,12 +68,12 @@ }, "Rollback": { "timeout_millis": 60000, - "retry_codes_name": "deadline_exceeded_internal_unavailable", + "retry_codes_name": "deadline_exceeded_aborted_internal_unavailable", "retry_params_name": "default" }, "RunQuery": { "timeout_millis": 300000, - "retry_codes_name": "deadline_exceeded_internal_unavailable", + "retry_codes_name": "deadline_exceeded_aborted_internal_unavailable", "retry_params_name": "default" }, "Write": { @@ -82,12 +83,12 @@ }, "Listen": { "timeout_millis": 86400000, - "retry_codes_name": "deadline_exceeded_internal_unavailable", + "retry_codes_name": "deadline_exceeded_aborted_internal_unavailable", "retry_params_name": "default" }, "ListCollectionIds": { "timeout_millis": 60000, - "retry_codes_name": "deadline_exceeded_internal_unavailable", + "retry_codes_name": "deadline_exceeded_aborted_internal_unavailable", "retry_params_name": "default" } } diff --git a/dev/src/v1beta1/firestore_client.ts b/dev/src/v1beta1/firestore_client.ts index bc2766bfe..738d5dd56 100644 --- a/dev/src/v1beta1/firestore_client.ts +++ b/dev/src/v1beta1/firestore_client.ts @@ -225,6 +225,9 @@ export class FirestoreClient { for (const methodName of firestoreStubMethods) { const innerCallPromise = this.firestoreStub.then( stub => (...args: Array<{}>) => { + if (this._terminated) { + return Promise.reject('The client has already been closed.'); + } return stub[methodName].apply(stub, args); }, (err: Error | null | undefined) => () => { @@ -245,9 +248,6 @@ export class FirestoreClient { callOptions?: CallOptions, callback?: APICallback ) => { - if (this._terminated) { - return Promise.reject('The client has already been closed.'); - } return apiCall(argument, callOptions, callback); }; } diff --git a/dev/synth.metadata b/dev/synth.metadata index 30e4f5221..49226d35c 100644 --- a/dev/synth.metadata +++ b/dev/synth.metadata @@ -1,12 +1,12 @@ { - "updateTime": "2019-12-18T12:16:40.490708Z", + "updateTime": "2020-01-03T12:14:28.989140Z", "sources": [ { "git": { "name": "googleapis", "remote": "https://github.com/googleapis/googleapis.git", - "sha": "3352100a15ede383f5ab3c34599f7a10a3d066fe", - "internalRef": "286065440" + "sha": "4d45a6399e9444fbddaeb1c86aabfde210723714", + "internalRef": "287908369" } }, { @@ -51,295 +51,292 @@ "path": "synth.metadata" }, { - "path": "protos/protos.json" + "path": "test/path.ts" }, { - "path": "protos/firestore_admin_v1_proto_api.d.ts" + "path": "test/gapic-firestore-v1beta1.ts" }, { - "path": "protos/update.sh" + "path": "test/fake-certificate.json" }, { - "path": "protos/insert-license.sh" + "path": "test/gapic-firestore-v1.ts" }, { - "path": "protos/firestore_v1_proto_api.js" + "path": "test/pool.ts" }, { - "path": "protos/firestore_v1beta1_proto_api.d.ts" + "path": "test/mocha.opts" }, { - "path": "protos/firestore_admin_v1_proto_api.js" + "path": "test/timestamp.ts" }, { - "path": "protos/firestore_v1beta1_proto_api.js" + "path": "test/document.ts" }, { - "path": "protos/firestore_v1_proto_api.d.ts" + "path": "test/index.ts" }, { - "path": "protos/google/rpc/status.proto" + "path": "test/query.ts" }, { - "path": "protos/google/firestore/v1beta1/document.proto" + "path": "test/watch.ts" }, { - "path": "protos/google/firestore/v1beta1/query.proto" + "path": "test/backoff.ts" }, { - "path": "protos/google/firestore/v1beta1/common.proto" + "path": "test/gapic-firestore_admin-v1.ts" }, { - "path": "protos/google/firestore/v1beta1/firestore.proto" + "path": "test/collection.ts" }, { - "path": "protos/google/firestore/v1beta1/write.proto" + "path": "test/field-value.ts" }, { - "path": "protos/google/firestore/admin/v1/field.proto" + "path": "test/order.ts" }, { - "path": "protos/google/firestore/admin/v1/location.proto" + "path": "test/typescript.ts" }, { - "path": "protos/google/firestore/admin/v1/firestore_admin.proto" + "path": "test/transaction.ts" }, { - "path": "protos/google/firestore/admin/v1/operation.proto" + "path": "test/write-batch.ts" }, { - "path": "protos/google/firestore/admin/v1/index.proto" + "path": "test/util/helpers.ts" }, { - "path": "protos/google/firestore/v1/document.proto" + "path": "system-test/.gitignore" }, { - "path": "protos/google/firestore/v1/query.proto" + "path": "system-test/firestore.ts" }, { - "path": "protos/google/firestore/v1/common.proto" + "path": "system-test/.eslintrc.yml" }, { - "path": "protos/google/firestore/v1/firestore.proto" + "path": "protos/firestore_admin_v1_proto_api.d.ts" }, { - "path": "protos/google/firestore/v1/write.proto" + "path": "protos/update.sh" }, { - "path": "protos/google/protobuf/struct.proto" + "path": "protos/firestore_v1beta1_proto_api.js" }, { - "path": "protos/google/protobuf/wrappers.proto" + "path": "protos/firestore_v1_proto_api.d.ts" }, { - "path": "protos/google/protobuf/empty.proto" + "path": "protos/firestore_v1_proto_api.js" }, { - "path": "protos/google/protobuf/timestamp.proto" + "path": "protos/protos.json" }, { - "path": "protos/google/protobuf/any.proto" + "path": "protos/firestore_v1beta1_proto_api.d.ts" }, { - "path": "protos/google/protobuf/field_mask.proto" + "path": "protos/firestore_admin_v1_proto_api.js" }, { - "path": "protos/google/longrunning/operations.proto" + "path": "protos/google/api/http.proto" }, { - "path": "protos/google/type/latlng.proto" + "path": "protos/google/api/annotations.proto" }, { - "path": "protos/google/api/resource.proto" + "path": "protos/google/api/field_behavior.proto" }, { - "path": "protos/google/api/client.proto" + "path": "protos/google/api/resource.proto" }, { - "path": "protos/google/api/http.proto" + "path": "protos/google/api/client.proto" }, { - "path": "protos/google/api/field_behavior.proto" + "path": "protos/google/type/latlng.proto" }, { - "path": "protos/google/api/annotations.proto" + "path": "protos/google/protobuf/field_mask.proto" }, { - "path": "test/gapic-firestore-v1beta1.ts" + "path": "protos/google/protobuf/struct.proto" }, { - "path": "test/transaction.ts" + "path": "protos/google/protobuf/empty.proto" }, { - "path": "test/watch.ts" + "path": "protos/google/protobuf/any.proto" }, { - "path": "test/field-value.ts" + "path": "protos/google/protobuf/wrappers.proto" }, { - "path": "test/query.ts" + "path": "protos/google/protobuf/timestamp.proto" }, { - "path": "test/typescript.ts" + "path": "protos/google/longrunning/operations.proto" }, { - "path": "test/document.ts" + "path": "protos/google/rpc/status.proto" }, { - "path": "test/fake-certificate.json" + "path": "protos/google/firestore/v1beta1/firestore.proto" }, { - "path": "test/path.ts" + "path": "protos/google/firestore/v1beta1/common.proto" }, { - "path": "test/collection.ts" + "path": "protos/google/firestore/v1beta1/query.proto" }, { - "path": "test/gapic-firestore_admin-v1.ts" + "path": "protos/google/firestore/v1beta1/write.proto" }, { - "path": "test/timestamp.ts" + "path": "protos/google/firestore/v1beta1/document.proto" }, { - "path": "test/backoff.ts" + "path": "protos/google/firestore/admin/v1/location.proto" }, { - "path": "test/pool.ts" + "path": "protos/google/firestore/admin/v1/index.proto" }, { - "path": "test/index.ts" + "path": "protos/google/firestore/admin/v1/firestore_admin.proto" }, { - "path": "test/write-batch.ts" + "path": "protos/google/firestore/admin/v1/operation.proto" }, { - "path": "test/mocha.opts" + "path": "protos/google/firestore/admin/v1/field.proto" }, { - "path": "test/order.ts" + "path": "protos/google/firestore/v1/firestore.proto" }, { - "path": "test/gapic-firestore-v1.ts" + "path": "protos/google/firestore/v1/common.proto" }, { - "path": "test/util/helpers.ts" + "path": "protos/google/firestore/v1/query.proto" }, { - "path": "system-test/.eslintrc.yml" + "path": "protos/google/firestore/v1/write.proto" }, { - "path": "system-test/.gitignore" + "path": "protos/google/firestore/v1/document.proto" }, { - "path": "system-test/firestore.ts" + "path": "src/path.ts" }, { - "path": "src/transaction.ts" + "path": "src/util.ts" }, { - "path": "src/watch.ts" + "path": "src/reference.ts" }, { - "path": "src/field-value.ts" + "path": "src/logger.ts" }, { - "path": "src/convert.ts" + "path": "src/types.ts" }, { - "path": "src/util.ts" + "path": "src/geo-point.ts" }, { - "path": "src/geo-point.ts" + "path": "src/pool.ts" }, { - "path": "src/reference.ts" + "path": "src/timestamp.ts" }, { "path": "src/document.ts" }, { - "path": "src/logger.ts" + "path": "src/convert.ts" }, { - "path": "src/path.ts" + "path": "src/index.ts" }, { - "path": "src/document-change.ts" + "path": "src/validate.ts" }, { - "path": "src/timestamp.ts" + "path": "src/serializer.ts" }, { - "path": "src/backoff.ts" + "path": "src/watch.ts" }, { - "path": "src/pool.ts" + "path": "src/backoff.ts" }, { - "path": "src/types.ts" + "path": "src/external-modules.d.ts" }, { - "path": "src/index.ts" + "path": "src/field-value.ts" }, { - "path": "src/write-batch.ts" + "path": "src/order.ts" }, { - "path": "src/external-modules.d.ts" + "path": "src/document-change.ts" }, { - "path": "src/serializer.ts" + "path": "src/transaction.ts" }, { - "path": "src/order.ts" + "path": "src/write-batch.ts" }, { - "path": "src/validate.ts" + "path": "src/v1beta1/index.ts" }, { "path": "src/v1beta1/firestore_client.ts" }, - { - "path": "src/v1beta1/firestore_proto_list.json" - }, { "path": "src/v1beta1/firestore_client_config.json" }, { - "path": "src/v1beta1/index.ts" + "path": "src/v1beta1/firestore_proto_list.json" }, { - "path": "src/v1/firestore_client.ts" + "path": "src/v1/index.ts" }, { - "path": "src/v1/firestore_admin_proto_list.json" + "path": "src/v1/firestore_client.ts" }, { - "path": "src/v1/firestore_proto_list.json" + "path": "src/v1/firestore_client_config.json" }, { - "path": "src/v1/firestore_client_config.json" + "path": "src/v1/firestore_admin_client_config.json" }, { "path": "src/v1/firestore_admin_client.ts" }, { - "path": "src/v1/index.ts" + "path": "src/v1/firestore_admin_proto_list.json" }, { - "path": "src/v1/firestore_admin_client_config.json" + "path": "src/v1/firestore_proto_list.json" }, { - "path": "conformance/test-suite.binproto" + "path": "conformance/test-definition.proto" }, { - "path": "conformance/.eslintrc.yml" + "path": "conformance/runner.ts" }, { - "path": "conformance/runner.ts" + "path": "conformance/test-suite.binproto" }, { - "path": "conformance/test-definition.proto" + "path": "conformance/.eslintrc.yml" } ] } \ No newline at end of file diff --git a/dev/test/index.ts b/dev/test/index.ts index 59060dd22..0ab27c308 100644 --- a/dev/test/index.ts +++ b/dev/test/index.ts @@ -1062,7 +1062,7 @@ describe('getAll() method', () => { [Status.PERMISSION_DENIED]: 1, [Status.RESOURCE_EXHAUSTED]: 1, [Status.FAILED_PRECONDITION]: 1, - [Status.ABORTED]: 1, + [Status.ABORTED]: 5, [Status.OUT_OF_RANGE]: 1, [Status.UNIMPLEMENTED]: 1, [Status.INTERNAL]: 5,