Skip to content
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

feat: add ability to close channels #824

Merged
merged 8 commits into from Dec 19, 2019
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
9 changes: 9 additions & 0 deletions dev/src/index.ts
Expand Up @@ -1007,6 +1007,15 @@ export class Firestore {
});
}

/**
* Terminates the Firestore client and closes all open streams.
*
* @return A Promise that resolves when the client is terminated.
thebrianchen marked this conversation as resolved.
Show resolved Hide resolved
*/
async terminate(): Promise<void> {
thebrianchen marked this conversation as resolved.
Show resolved Hide resolved
await this._clientPool.terminate();
thebrianchen marked this conversation as resolved.
Show resolved Hide resolved
}

/**
* Initializes the client if it is not already initialized. All methods in the
* SDK can be used after this method completes.
Expand Down
17 changes: 17 additions & 0 deletions dev/src/pool.ts
Expand Up @@ -35,6 +35,12 @@ export class ClientPool<T> {
*/
private activeClients: Map<T, number> = new Map();

/**
* Whether the Firestore instance has been terminated. Once terminated, the
* ClientPool can longer schedule new operations.
*/
private terminated = false;

/**
* @param concurrentOperationLimit The number of operations that each client
* can handle.
Expand Down Expand Up @@ -148,6 +154,9 @@ export class ClientPool<T> {
* @private
*/
run<V>(requestTag: string, op: (client: T) => Promise<V>): Promise<V> {
if (this.terminated) {
throw new Error('The client has already been terminated');
}
const client = this.acquire(requestTag);

return op(client)
Expand All @@ -161,6 +170,14 @@ export class ClientPool<T> {
});
}

async terminate(): Promise<void> {
this.terminated = true;
for (const [client, _requestCount] of this.activeClients) {
this.activeClients.delete(client);
await this.clientDestructor(client);
}
}

/**
* Deletes clients that are no longer executing operations. Keeps up to one
* idle client to reduce future initialization costs.
Expand Down
17 changes: 17 additions & 0 deletions dev/test/pool.ts
Expand Up @@ -191,4 +191,21 @@ describe('Client pool', () => {
);
return expect(op).to.eventually.be.rejectedWith('Generated error');
});

it('rejects subsequent operations after being terminated', () => {
const clientPool = new ClientPool<{}>(1, () => {
return {};
});

return clientPool
.terminate()
.then(() => {
clientPool.run(REQUEST_TAG, () =>
Promise.reject('Call to run() should have failed')
);
})
.catch((err: Error) => {
expect(err.message).to.equal('The client has already been terminated');
});
});
});
7 changes: 7 additions & 0 deletions types/firestore.d.ts
Expand Up @@ -154,6 +154,13 @@ declare namespace FirebaseFirestore {
getAll(...documentRefsOrReadOptions: Array<DocumentReference|ReadOptions>):
Promise<DocumentSnapshot[]>;

/**
* Terminates the Firestore client and closes all open streams.
*
* @return A Promise that resolves when the client is terminated.
*/
terminate(): Promise<void>;

/**
* Fetches the root collections that are associated with this Firestore
* database.
Expand Down