Open dgpc opened 2 years ago
@yuchenshi I think you aren;t the right person for this but probably know who is. Could you pass this along to the firestore team?
I am also seeing similar regressions dealing with transactions. firebase-tools 10.4.2 / emulator v1.13.1 is the latest version I can use for now.
FWIW here's one of the test runs where some tests fail due to "Transaction is invalid or closed." related errors:
/code/node_modules/@grpc/grpc-js/build/src/call.js:31
return Object.assign(new Error(message), status);
^
Error: 3 INVALID_ARGUMENT: Transaction is invalid or closed.
at Object.callErrorFromStatus (/code/node_modules/@grpc/grpc-js/src/call.ts:81:24)
at Object.onReceiveStatus (/code/node_modules/@grpc/grpc-js/src/client.ts:577:32)
at Object.onReceiveStatus (/code/node_modules/@grpc/grpc-js/src/client-interceptors.ts:424:48)
at /code/node_modules/@grpc/grpc-js/src/call-stream.ts:323:24
at processTicksAndRejections (node:internal/process/task_queues:78:11) {
code: 3,
details: 'Transaction is invalid or closed.',
metadata: Metadata {
internalRepr: Map(1) { 'content-type' => [ 'application/grpc' ] },
options: {}
}
}
Here's some firestore-debug.log outputs for a stacktrace one of those tests.
May 07, 2022 7:31:23 AM com.google.cloud.datastore.emulator.impl.util.WrappedStreamObserver onError
INFO: operation failed: Can't swap from CLOSED to ACTIVE.
com.google.cloud.datastore.core.exception.DatastoreException: Can't swap from CLOSED to ACTIVE.
at com.google.cloud.datastore.emulator.impl.transactions.EmulatorTransactionManager.toActive(EmulatorTransactionManager.java:454)
at com.google.cloud.datastore.emulator.impl.storage.FlatLocalEntityStore$StronglyConsistentReadView.<init>(FlatLocalEntityStore.java:94)
at com.google.cloud.datastore.emulator.impl.storage.FlatLocalEntityStore$StronglyConsistentReadView.<init>(FlatLocalEntityStore.java:98)
at com.google.cloud.datastore.emulator.impl.storage.FlatLocalEntityStore.read(FlatLocalEntityStore.java:62)
at com.google.cloud.datastore.emulator.impl.CloudFirestoreV1.transactionalRead(CloudFirestoreV1.java:1026)
at com.google.cloud.datastore.emulator.impl.CloudFirestoreV1.lambda$read$26(CloudFirestoreV1.java:1016)
at com.google.cloud.datastore.emulator.impl.transactions.EmulatorTransactionManager$ReadWriteTransaction.fold(EmulatorTransactionManager.java:359)
at com.google.cloud.datastore.emulator.impl.CloudFirestoreV1.read(CloudFirestoreV1.java:1014)
at com.google.cloud.datastore.emulator.impl.CloudFirestoreV1.batchGetDocuments(CloudFirestoreV1.java:397)
at com.google.cloud.datastore.emulator.impl.CloudFirestoreV1Router.batchGetDocuments(CloudFirestoreV1Router.java:125)
at com.google.cloud.datastore.emulator.firestore.v1.FirestoreV1GrpcAdapter$1.lambda$batchGetDocuments$6(FirestoreV1GrpcAdapter.java:146)
at com.google.cloud.datastore.emulator.firestore.v1.FirestoreV1GrpcAdapter.streaming(FirestoreV1GrpcAdapter.java:79)
at com.google.cloud.datastore.emulator.firestore.v1.FirestoreV1GrpcAdapter.access$100(FirestoreV1GrpcAdapter.java:41)
at com.google.cloud.datastore.emulator.firestore.v1.FirestoreV1GrpcAdapter$1.batchGetDocuments(FirestoreV1GrpcAdapter.java:146)
at com.google.firestore.v1.FirestoreGrpc$MethodHandlers.invoke(FirestoreGrpc.java:1278)
at io.grpc.stub.ServerCalls$UnaryServerCallHandler$UnaryServerCallListener.onHalfClose(ServerCalls.java:182)
at io.grpc.PartialForwardingServerCallListener.onHalfClose(PartialForwardingServerCallListener.java:35)
at io.grpc.ForwardingServerCallListener.onHalfClose(ForwardingServerCallListener.java:23)
at io.grpc.ForwardingServerCallListener$SimpleForwardingServerCallListener.onHalfClose(ForwardingServerCallListener.java:40)
at io.grpc.Contexts$ContextualizedServerCallListener.onHalfClose(Contexts.java:86)
at io.grpc.PartialForwardingServerCallListener.onHalfClose(PartialForwardingServerCallListener.java:35)
at io.grpc.ForwardingServerCallListener.onHalfClose(ForwardingServerCallListener.java:23)
at io.grpc.ForwardingServerCallListener$SimpleForwardingServerCallListener.onHalfClose(ForwardingServerCallListener.java:40)
at io.grpc.Contexts$ContextualizedServerCallListener.onHalfClose(Contexts.java:86)
at io.grpc.internal.ServerCallImpl$ServerStreamListenerImpl.halfClosed(ServerCallImpl.java:340)
at io.grpc.internal.ServerImpl$JumpToApplicationThreadServerStreamListener$1HalfClosed.runInContext(ServerImpl.java:866)
at io.grpc.internal.ContextRunnable.run(ContextRunnable.java:37)
at io.grpc.internal.SerializingExecutor.run(SerializingExecutor.java:133)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:829)
May 07, 2022 7:35:57 AM com.google.cloud.datastore.emulator.impl.util.WrappedStreamObserver onError
INFO: operation failed: Transaction is invalid or closed.
com.google.cloud.datastore.core.exception.DatastoreException: Transaction is invalid or closed.
at com.google.cloud.datastore.emulator.impl.transactions.EmulatorTransactionManager.reuseExisting(EmulatorTransactionManager.java:207)
at com.google.cloud.datastore.emulator.impl.transactions.EmulatorTransactionManager.create(EmulatorTransactionManager.java:109)
at com.google.cloud.datastore.emulator.impl.CloudFirestoreV1.batchGetDocuments(CloudFirestoreV1.java:394)
at com.google.cloud.datastore.emulator.impl.CloudFirestoreV1Router.batchGetDocuments(CloudFirestoreV1Router.java:125)
at com.google.cloud.datastore.emulator.firestore.v1.FirestoreV1GrpcAdapter$1.lambda$batchGetDocuments$6(FirestoreV1GrpcAdapter.java:146)
at com.google.cloud.datastore.emulator.firestore.v1.FirestoreV1GrpcAdapter.streaming(FirestoreV1GrpcAdapter.java:79)
at com.google.cloud.datastore.emulator.firestore.v1.FirestoreV1GrpcAdapter.access$100(FirestoreV1GrpcAdapter.java:41)
at com.google.cloud.datastore.emulator.firestore.v1.FirestoreV1GrpcAdapter$1.batchGetDocuments(FirestoreV1GrpcAdapter.java:146)
at com.google.firestore.v1.FirestoreGrpc$MethodHandlers.invoke(FirestoreGrpc.java:1278)
at io.grpc.stub.ServerCalls$UnaryServerCallHandler$UnaryServerCallListener.onHalfClose(ServerCalls.java:182)
at io.grpc.PartialForwardingServerCallListener.onHalfClose(PartialForwardingServerCallListener.java:35)
at io.grpc.ForwardingServerCallListener.onHalfClose(ForwardingServerCallListener.java:23)
at io.grpc.ForwardingServerCallListener$SimpleForwardingServerCallListener.onHalfClose(ForwardingServerCallListener.java:40)
at io.grpc.Contexts$ContextualizedServerCallListener.onHalfClose(Contexts.java:86)
at io.grpc.PartialForwardingServerCallListener.onHalfClose(PartialForwardingServerCallListener.java:35)
at io.grpc.ForwardingServerCallListener.onHalfClose(ForwardingServerCallListener.java:23)
at io.grpc.ForwardingServerCallListener$SimpleForwardingServerCallListener.onHalfClose(ForwardingServerCallListener.java:40)
at io.grpc.Contexts$ContextualizedServerCallListener.onHalfClose(Contexts.java:86)
at io.grpc.internal.ServerCallImpl$ServerStreamListenerImpl.halfClosed(ServerCallImpl.java:340)
at io.grpc.internal.ServerImpl$JumpToApplicationThreadServerStreamListener$1HalfClosed.runInContext(ServerImpl.java:866)
at io.grpc.internal.ContextRunnable.run(ContextRunnable.java:37)
at io.grpc.internal.SerializingExecutor.run(SerializingExecutor.java:133)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:829)
I ran into this earlier when firebase-tools 10.5.0 / emulator v1.14.1 was released and figured out it was probably more related to the emulator rather than firebase-tools. Emulator v1.14.1 had more transactional timeout related issues in my tests.
This is probably enough for a separate report, but:
I'm guessing the way the emulator communicated via grpc changed which caused some timings in promises to change. I fixed most of the tests, but there's still one that seems to have a weird race condition left related to terminating a '@google-cloud/firestore' Firestore instance after the tests end.
It causes this relatively simple test to "sometimes" fail:
it('should create a new document accessor instance that uses the passed transaction context.', async () => {
let ref: DocumentReference<MockItem>;
await firestore.runTransaction(async (transaction: Transaction) => {
const documentAccessor = firestoreCollection.documentAccessorForTransaction(transaction);
const document = documentAccessor.newDocument();
ref = document.documentRef as DocumentReference<MockItem>;
await document.accessor.set({ test: true });
});
expect(ref!).toBeDefined();
const loadedDoc = firestoreCollection.documentAccessor().loadDocument(ref!);
const loadedData: DocumentSnapshot<MockItem> = await loadedDoc.accessor.get() as DocumentSnapshot<MockItem>;
expect(loadedData).toBeDefined();
expect(loadedData.data()).toBeDefined();
expect(loadedData.data()?.test).toBe(true);
});
The following setup/teardown code is also executed before/after the test:
setupInstance: async (config) => {
const drivers = makeTestingFirestoreDrivers(googleCloudFirestoreDrivers());
const projectId = 'firebase-server-test-' + new Date().getTime();
const firestore = new Firestore({
projectId,
host: config.host,
port: config.port,
maxIdleChannels: 0
});
return new GoogleCloudTestFirestoreInstance(drivers, firestore);
},
teardownInstance: async (instance, config) => {
await (instance.firestore as Firestore).terminate();
}
Here is the error that is popping up and sometimes causing the tests to fail:
/code/node_modules/@grpc/grpc-js/build/src/call.js:31
return Object.assign(new Error(message), status);
^
Error: 3 INVALID_ARGUMENT: Transaction is invalid or closed.
at Object.callErrorFromStatus (/code/node_modules/@grpc/grpc-js/src/call.ts:81:24)
at Object.onReceiveStatus (/code/node_modules/@grpc/grpc-js/src/client.ts:577:32)
at Object.onReceiveStatus (/code/node_modules/@grpc/grpc-js/src/client-interceptors.ts:424:48)
at /code/node_modules/@grpc/grpc-js/src/call-stream.ts:323:24
at processTicksAndRejections (node:internal/process/task_queues:78:11) {
code: 3,
details: 'Transaction is invalid or closed.',
metadata: Metadata {
internalRepr: Map(1) { 'content-type' => [ 'application/grpc' ] },
options: {}
}
}
However, this happens inconsistently. Sometimes the tests passes without this occurring, other times it fails.
● FirestoreCollection › documentAccessor() › should create a new document accessor instance that uses the passed batch context.
3 INVALID_ARGUMENT: Transaction is invalid or closed.
at Object.callErrorFromStatus (../../node_modules/@grpc/grpc-js/src/call.ts:81:24)
at Object.onReceiveStatus (../../node_modules/@grpc/grpc-js/src/client.ts:577:32)
at Object.onReceiveStatus (../../node_modules/@grpc/grpc-js/src/client-interceptors.ts:424:48)
at ../../node_modules/@grpc/grpc-js/src/call-stream.ts:323:24
Removing the teardown code helps the transaction test above, but other issues seem to pop up. These issues don't occur in firebase-tools 10.4.2 / emulator v1.13.1.
It seems like there are promises internally that are resolving too early or resolving inconsistently, potentially as a result of transaction changes in the emulator.
EDIT
I ran across a random post somewhere saying you have to perform a read and a write for a transaction. In retrospect that makes sense. After updating those effected tests they pass properly now.
https://github.com/dereekb/dbx-components/commit/2d448c5c3deea8feb82180c5aeaedb2fdf9a105a
Ignore my post, unless you hand similar issues, in which case I'd tell you to double check that you're using transactions/write batches correctly.
[REQUIRED] Environment info
firebase-tools:
firebase-tools 10.7.1 / emulator v1.14.3 fails firebase-tools 10.5.0 / emulator v1.14.1 fails
firebase-tools 10.4.2 / emulator v1.13.1 passes
Platform:
Verified on both macOS and Debian Linux
[REQUIRED] Test case
[REQUIRED] Steps to reproduce
[REQUIRED] Expected behavior
Under firestore emulator v1.13.1 calling
GetAll
with an empty slice of refs returns anil
error and an empty list of documents, same behavior as the production firestore.[REQUIRED] Actual behavior
Under firestore emulator v1.14.1 and v1.14.3 (bundled with the latest firebase-tools release) we now get an Unknown RPC error code:
With full debug info: