Skip to content

rename shutdown to terminate and publish it #2116

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Aug 27, 2019
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions packages/firebase/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6222,6 +6222,44 @@ declare namespace firebase.firestore {
*/
disableNetwork(): Promise<void>;

/**
* Waits until all currently pending writes for the active user have been acknowledged by the
* backend.
*
* The returned Promise resolves immediately if there are no outstanding writes. Otherwise, the
* Promise waits for all previously issued writes (including those written in a previous app
* session), but it does not wait for writes that were added after the method is called. If you
* wish to wait for additional writes, you have to call `waitForPendingWrites()` again.
*
* Any outstanding `waitForPendingWrites()` Promises are rejected during user changes.
*
* @return A Promise which resolves when all currently pending writes have been
* acknowledged by the backend.
*/
waitForPendingWrites(): Promise<void>;

/**
* Terminates this Firestore instance.
*
* After calling `terminate()` only the `clearPersistence()` method may be used. Any other method
* will throw a `FirestoreError`.
*
* To restart after termination, create a new instance of FirebaseFirestore with
* `firebase.firestore()`.
*
* Termination does not cancel any pending writes, and any promises that are awaiting a response
* from the server will not be resolved. If you have persistence enabled, the next time you
* start this instance, it will resume sending these writes to the server.
*
* Note: Under normal circumstances, calling `terminate()` is not required. This
* method is useful only when you want to force this instance to release all of its resources or
* in combination with `clearPersistence()` to ensure that all local state is destroyed
* between test runs.
*
* @return A promise that is resolved when the instance has been successfully terminated.
*/
terminate(): Promise<void>;

/**
* @hidden
*/
Expand Down
38 changes: 38 additions & 0 deletions packages/firestore-types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,44 @@ export class FirebaseFirestore {
*/
disableNetwork(): Promise<void>;

/**
* Waits until all currently pending writes for the active user have been acknowledged by the
* backend.
*
* The returned Promise resolves immediately if there are no outstanding writes. Otherwise, the
* Promise waits for all previously issued writes (including those written in a previous app
* session), but it does not wait for writes that were added after the method is called. If you
* wish to wait for additional writes, you have to call `waitForPendingWrites()` again.
*
* Any outstanding `waitForPendingWrites()` Promises are rejected during user changes.
*
* @return A Promise which resolves when all currently pending writes have been
* acknowledged by the backend.
*/
waitForPendingWrites(): Promise<void>;

/**
* Terminates this Firestore instance.
*
* After calling `terminate()` only the `clearPersistence()` method may be used. Any other method
* will throw a `FirestoreError`.
*
* To restart after termination, create a new instance of FirebaseFirestore with
* `firebase.firestore()`.
*
* Termination does not cancel any pending writes, and any promises that are awaiting a response
* from the server will not be resolved. If you have persistence enabled, the next time you
* start this instance, it will resume sending these writes to the server.
*
* Note: Under normal circumstances, calling `terminate()` is not required. This
* method is useful only when you want to force this instance to release all of its resources or
* in combination with `clearPersistence()` to ensure that all local state is destroyed
* between test runs.
*
* @return A promise that is resolved when the instance has been successfully terminated.
*/
terminate(): Promise<void>;

INTERNAL: { delete: () => Promise<void> };
}

Expand Down
44 changes: 33 additions & 11 deletions packages/firestore/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,23 +1,45 @@

# Unreleased
# Unreleased (1.5.0)
- [feature] Added a `Firestore.waitForPendingWrites()` method which
allows users to wait until all pending writes are acknowledged by the
Firestore backend.
- [feature] Added a `Firestore.terminate()` method which terminates
the instance, releasing any held resources. Once it completes, you can
optionally call `Firestore.clearPersistence()` to wipe persisted Firestore
data from disk.

# 1.4.10
- [changed] Transactions now perform exponential backoff before retrying.
This means transactions on highly contended documents are more likely to
succeed.

# 1.4.6
- [changed] Transactions are now more flexible. Some sequences of operations
that were previously incorrectly disallowed are now allowed. For example,
after reading a document that doesn't exist, you can now set it multiple
times successfully in a transaction.

# 1.4.5
- [fixed] Fixed an issue where query results were temporarily missing
documents that previously had not matched but had been updated to now
match the query (https://github.com/firebase/firebase-android-sdk/issues/155).

# 1.4.4
- [fixed] Fixed an internal assertion that was triggered when an update
with a `FieldValue.serverTimestamp()` and an update with a
`FieldValue.increment()` were pending for the same document.
- [feature] Added `clearPersistence()`, which clears the persistent storage
including pending writes and cached documents. This is intended to help
write reliable tests (#449).

# 1.4.0
- [changed] Added logging and a custom error message to help users hitting
https://bugs.webkit.org/show_bug.cgi?id=197050 (a bug in iOS 12.2 causing
the SDK to potentially crash when persistence is enabled).
- [fixed] Fixed an issue for environments missing `window.addEventListener`,
such as in React Native with Expo (#1824).
- [changed] Transactions are now more flexible. Some sequences of operations
that were previously incorrectly disallowed are now allowed. For example,
after reading a document that doesn't exist, you can now set it multiple
times successfully in a transaction.
- [changed] Transactions now perform exponential backoff before retrying.
This means transactions on highly contended documents are more likely to
succeed.

# 1.3.5
- [feature] Added `clearPersistence()`, which clears the persistent storage
including pending writes and cached documents. This is intended to help
write reliable tests (#449).

# 1.3.3
- [changed] Firestore now recovers more quickly after network connectivity
Expand Down
47 changes: 6 additions & 41 deletions packages/firestore/src/api/database.ts
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,7 @@ export class Firestore implements firestore.FirebaseFirestore, FirebaseService {
try {
if (
this._firestoreClient !== undefined &&
!this._firestoreClient.clientShutdown
!this._firestoreClient.clientTerminated
) {
throw new FirestoreError(
Code.FAILED_PRECONDITION,
Expand All @@ -437,52 +437,17 @@ export class Firestore implements firestore.FirebaseFirestore, FirebaseService {
return deferred.promise;
}

/**
* Shuts down this Firestore instance.
*
* After shutdown only the `clearPersistence()` method may be used. Any other method
* will throw a `FirestoreError`.
*
* To restart after shutdown, simply create a new instance of FirebaseFirestore with
* `firebase.firestore()`.
*
* Shutdown does not cancel any pending writes and any promises that are awaiting a response
* from the server will not be resolved. If you have persistence enabled, the next time you
* start this instance, it will resume attempting to send these writes to the server.
*
* Note: Under normal circumstances, calling `shutdown()` is not required. This
* method is useful only when you want to force this instance to release all of its resources or
* in combination with `clearPersistence()` to ensure that all local state is destroyed
* between test runs.
*
* @return A promise that is resolved when the instance has been successfully shut down.
*/
// TODO(b/135755126): make this public.
_shutdown(): Promise<void> {
terminate(): Promise<void> {
(this.app as _FirebaseApp)._removeServiceInstance('firestore');
return this.INTERNAL.delete();
}

get _isShutdown(): boolean {
get _isTerminated(): boolean {
this.ensureClientConfigured();
return this._firestoreClient!.clientShutdown;
return this._firestoreClient!.clientTerminated;
}

/**
* Waits until all currently pending writes for the active user have been acknowledged by the
* backend.
*
* The returned Promise resolves immediately if there are no outstanding writes. Otherwise, the
* Promise waits for all previously issued writes (including those written in a previous app
* session), but it does not wait for writes that were added after the method is called. If you
* wish to wait for additional writes, you have to call `waitForPendingWrites()` again.
*
* Any outstanding `waitForPendingWrites()` Promises are rejected during user changes.
*
* @return A Promise which resolves when all currently pending writes have been
* acknowledged by the backend.
*/
_waitForPendingWrites(): Promise<void> {
waitForPendingWrites(): Promise<void> {
this.ensureClientConfigured();
return this._firestoreClient!.waitForPendingWrites();
}
Expand Down Expand Up @@ -581,7 +546,7 @@ export class Firestore implements firestore.FirebaseFirestore, FirebaseService {
// The client must be initalized to ensure that all subsequent API usage
// throws an exception.
this.ensureClientConfigured();
await this._firestoreClient!.shutdown();
await this._firestoreClient!.terminate();
}
};

Expand Down
46 changes: 23 additions & 23 deletions packages/firestore/src/core/firestore_client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ export class FirestoreClient {
* unconditionally resolved.
*/
start(persistenceSettings: InternalPersistenceSettings): Promise<void> {
this.verifyNotShutdown();
this.verifyNotTerminated();
// We defer our initialization until we get the current user from
// setChangeListener(). We block the async queue until we got the initial
// user and the initialization is completed. This will prevent any scheduled
Expand Down Expand Up @@ -208,7 +208,7 @@ export class FirestoreClient {

/** Enables the network connection and requeues all pending operations. */
enableNetwork(): Promise<void> {
this.verifyNotShutdown();
this.verifyNotTerminated();
return this.asyncQueue.enqueue(() => {
return this.syncEngine.enableNetwork();
});
Expand Down Expand Up @@ -305,14 +305,14 @@ export class FirestoreClient {
}

/**
* Checks that the client has not been shutdown. Ensures that other methods on
* this class cannot be called after the client is shutdown.
* Checks that the client has not been terminated. Ensures that other methods on
* this class cannot be called after the client is terminated.
*/
private verifyNotShutdown(): void {
private verifyNotTerminated(): void {
if (this.asyncQueue.isShuttingDown) {
throw new FirestoreError(
Code.FAILED_PRECONDITION,
'The client has already been shutdown.'
'The client has already been terminated.'
);
}
}
Expand Down Expand Up @@ -482,10 +482,10 @@ export class FirestoreClient {
}
});

// When a user calls clearPersistence() in one client, all other clientfs
// need to shut down to allow the delete to succeed.
// When a user calls clearPersistence() in one client, all other clients
// need to be terminated to allow the delete to succeed.
await this.persistence.setDatabaseDeletedListener(async () => {
await this.shutdown();
await this.terminate();
});
});
}
Expand All @@ -499,13 +499,13 @@ export class FirestoreClient {

/** Disables the network connection. Pending operations will not complete. */
disableNetwork(): Promise<void> {
this.verifyNotShutdown();
this.verifyNotTerminated();
return this.asyncQueue.enqueue(() => {
return this.syncEngine.disableNetwork();
});
}

shutdown(): Promise<void> {
terminate(): Promise<void> {
return this.asyncQueue.enqueueAndInitiateShutdown(async () => {
// PORTING NOTE: LocalStore does not need an explicit shutdown on web.
if (this.lruScheduler) {
Expand All @@ -528,7 +528,7 @@ export class FirestoreClient {
* or rejection.
*/
waitForPendingWrites(): Promise<void> {
this.verifyNotShutdown();
this.verifyNotTerminated();

const deferred = new Deferred<void>();
this.asyncQueue.enqueueAndForget(() => {
Expand All @@ -542,7 +542,7 @@ export class FirestoreClient {
observer: Observer<ViewSnapshot>,
options: ListenOptions
): QueryListener {
this.verifyNotShutdown();
this.verifyNotTerminated();
const listener = new QueryListener(query, observer, options);
this.asyncQueue.enqueueAndForget(() => {
return this.eventMgr.listen(listener);
Expand All @@ -551,9 +551,9 @@ export class FirestoreClient {
}

unlisten(listener: QueryListener): void {
// Checks for shutdown but does not raise error, allowing unlisten after
// shutdown to be a no-op.
if (this.clientShutdown) {
// Checks for termination but does not raise error, allowing unlisten after
// termination to be a no-op.
if (this.clientTerminated) {
return;
}
this.asyncQueue.enqueueAndForget(() => {
Expand All @@ -562,7 +562,7 @@ export class FirestoreClient {
}

getDocumentFromLocalCache(docKey: DocumentKey): Promise<Document | null> {
this.verifyNotShutdown();
this.verifyNotTerminated();
return this.asyncQueue
.enqueue(() => {
return this.localStore.readDocument(docKey);
Expand All @@ -585,7 +585,7 @@ export class FirestoreClient {
}

getDocumentsFromLocalCache(query: Query): Promise<ViewSnapshot> {
this.verifyNotShutdown();
this.verifyNotTerminated();
return this.asyncQueue
.enqueue(() => {
return this.localStore.executeQuery(query);
Expand All @@ -605,7 +605,7 @@ export class FirestoreClient {
}

write(mutations: Mutation[]): Promise<void> {
this.verifyNotShutdown();
this.verifyNotTerminated();
const deferred = new Deferred<void>();
this.asyncQueue.enqueueAndForget(() =>
this.syncEngine.write(mutations, deferred)
Expand All @@ -617,17 +617,17 @@ export class FirestoreClient {
return this.databaseInfo.databaseId;
}

get clientShutdown(): boolean {
get clientTerminated(): boolean {
// Technically, the asyncQueue is still running, but only accepting operations
// related to shutdown or supposed to be run after shutdown. It is effectively
// shut down to the eyes of users.
// related to termination or supposed to be run after termination. It is effectively
// terminated to the eyes of users.
return this.asyncQueue.isShuttingDown;
}

transaction<T>(
updateFunction: (transaction: Transaction) => Promise<T>
): Promise<T> {
this.verifyNotShutdown();
this.verifyNotTerminated();
const deferred = new Deferred<T>();
this.asyncQueue.enqueueAndForget(() => {
this.syncEngine.runTransaction(this.asyncQueue, updateFunction, deferred);
Expand Down
Loading