Skip to content
6 changes: 1 addition & 5 deletions packages/firebase/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6225,11 +6225,7 @@ declare namespace firebase.firestore {
/**
* @hidden
*/
INTERNAL: {
delete: () => Promise<void>;
shutdown: () => Promise<void>;
isShutdown: () => boolean;
};
INTERNAL: { delete: () => Promise<void> };
}

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

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

/**
Expand Down
66 changes: 33 additions & 33 deletions packages/firestore/src/api/database.ts
Original file line number Diff line number Diff line change
Expand Up @@ -447,6 +447,39 @@ export class Firestore implements firestore.FirebaseFirestore, FirebaseService {
return deferred.promise;
}

/**
* Shuts down this Firestore instance.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

leading spaces seems off... If you run yarn lint from packages/firestore, it should complain about this (and it's complaining in the CI build too).

*
* 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> {
(this.app as _FirebaseApp)._removeServiceInstance(
'firestore'
);
return this.INTERNAL.delete();
}

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

ensureClientConfigured(): FirestoreClient {
if (!this._firestoreClient) {
// Kick off starting the client but don't actually wait for it.
Expand Down Expand Up @@ -538,44 +571,11 @@ export class Firestore implements firestore.FirebaseFirestore, FirebaseService {
}

INTERNAL = {
// TODO(b/135755126): Make this public
delete: async (): Promise<void> => {
// The client must be initalized to ensure that all subsequent API usage
// throws an exception.
this.ensureClientConfigured();
await this._firestoreClient!.shutdown();
},

/**
* Shuts down this Firestore instance.
*
* After shutdown only the `clearPersistence()` method may be used. Any other method
* will throw an `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. 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> => {
(this._config.firebaseApp as _FirebaseApp)._removeServiceInstance(
'firestore'
);
return this.INTERNAL.delete();
},

isShutdown: (): boolean => {
return this._firestoreClient!.clientShutdown;
}
};

Expand Down
2 changes: 1 addition & 1 deletion packages/firestore/src/core/firestore_client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -506,7 +506,7 @@ export class FirestoreClient {
}

shutdown(): Promise<void> {
return this.asyncQueue.enqueueAndInitilizeShutdown(async () => {
return this.asyncQueue.enqueueAndInitiateShutdown(async () => {
// PORTING NOTE: LocalStore does not need an explicit shutdown on web.
if (this.lruScheduler) {
this.lruScheduler.stop();
Expand Down
16 changes: 4 additions & 12 deletions packages/firestore/src/util/async_queue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,6 @@ export class AsyncQueue {
op: () => Promise<T>
): void {
this.verifyNotFailed();
// tslint:disable-next-line:no-floating-promises
this.enqueueInternal(op);
}

Expand All @@ -238,7 +237,6 @@ export class AsyncQueue {
op: () => Promise<T>
): Promise<T> {
this.verifyNotFailed();
// tslint:disable-next-line:no-floating-promises
return this.enqueueInternal(op);
}

Expand All @@ -249,18 +247,12 @@ export class AsyncQueue {
* Once this method is called, the only possible way to request running an operation
* is through `enqueueAndForgetEvenAfterShutdown`.
*/
enqueueAndInitilizeShutdown<T extends unknown>(
op: () => Promise<T>
): Promise<T> {
async enqueueAndInitiateShutdown(op: () => Promise<void>): Promise<void> {
this.verifyNotFailed();
if (this._isShuttingDown) {
// Return a Promise resolves right away if it is already shutdown.
return new Promise<T>(resolve => resolve(undefined));
if (!this._isShuttingDown) {
this._isShuttingDown = true;
await this.enqueueEvenAfterShutdown(op);
}

const promise = this.enqueueInternal(op);
this._isShuttingDown = true;
return promise;
}

/**
Expand Down
10 changes: 5 additions & 5 deletions packages/firestore/test/integration/api/database.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1073,7 +1073,7 @@ apiDescribe('Database', (persistence: boolean) => {
it('can start a new instance after shut down', async () => {
return withTestDoc(persistence, async docRef => {
const firestore = docRef.firestore;
await firestore.INTERNAL.shutdown();
await (firestore as any)._shutdown();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

any is disallowed by the linter (again, running yarn lint from packages/firestore will complain). So you'll need a lint suppression. I'd recommend trying not to repeat it over and over. So you could create a helper like Brian did for clearPersistence(): 7a15e7e#diff-1422c3d56f022a40f00b40d264351ffdL109

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.


const newFirestore = firebase.firestore!(firestore.app);
expect(newFirestore).to.not.equal(firestore);
Expand All @@ -1092,14 +1092,14 @@ apiDescribe('Database', (persistence: boolean) => {
const app = docRef.firestore.app;
await app.delete();

expect(docRef.firestore.INTERNAL.isShutdown()).to.be.true;
expect((docRef.firestore as any)._isShutdown).to.be.true;
});
});

it('new operation after shutdown should throw', async () => {
await withTestDoc(persistence, async docRef => {
const firestore = docRef.firestore;
await firestore.INTERNAL.shutdown();
await (firestore as any)._shutdown();

expect(() => {
firestore.doc(docRef.path).set({ foo: 'bar' });
Expand All @@ -1110,8 +1110,8 @@ apiDescribe('Database', (persistence: boolean) => {
it('calling shutdown mutiple times should proceed', async () => {
await withTestDoc(persistence, async docRef => {
const firestore = docRef.firestore;
await firestore.INTERNAL.shutdown();
await firestore.INTERNAL.shutdown();
await (firestore as any)._shutdown();
await (firestore as any)._shutdown();

expect(() => {
firestore.doc(docRef.path).set({ foo: 'bar' });
Expand Down
7 changes: 3 additions & 4 deletions packages/firestore/test/unit/util/async_queue.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -213,18 +213,17 @@ describe('AsyncQueue', () => {
it('Schedules operaions with respect to shut down', async () => {
const queue = new AsyncQueue();
const completedSteps: number[] = [];
const doStep = (n: number): Promise<number> =>
const doStep = (n: number): Promise<void> =>
defer(() => {
const result = completedSteps.push(n);
return result;
completedSteps.push(n);
});

queue.enqueueAndForget(() => doStep(1));

// After this call, only operations requested via
// `enqueueAndForgetEvenAfterShutdown` gets executed.
// tslint:disable-next-line:no-floating-promises
queue.enqueueAndInitilizeShutdown(() => doStep(2));
queue.enqueueAndInitiateShutdown(() => doStep(2));
queue.enqueueAndForget(() => doStep(3));
queue.enqueueAndForgetEvenAfterShutdown(() => doStep(4));

Expand Down