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

Allowing 101 listeners #256

Merged
merged 9 commits into from Jul 13, 2018
Merged

Allowing 101 listeners #256

merged 9 commits into from Jul 13, 2018

Conversation

schmidt-sebastian
Copy link
Contributor

@schmidt-sebastian schmidt-sebastian commented Jul 12, 2018

The GAPIC client that handles all of Firestore's networking is limited to 100 connections. This PR lift this limit by replacing the static GAPIC client with a pool of clients. If more than 100 operations run concurrently, we create additional clients.

@googlebot googlebot added the cla: yes This human has signed the Contributor License Agreement. label Jul 12, 2018
@codecov
Copy link

codecov bot commented Jul 12, 2018

Codecov Report

Merging #256 into master will not change coverage.
The diff coverage is 100%.

Impacted file tree graph

@@          Coverage Diff          @@
##           master   #256   +/-   ##
=====================================
  Coverage     100%   100%           
=====================================
  Files          12     12           
  Lines        2104   2119   +15     
  Branches      457    458    +1     
=====================================
+ Hits         2104   2119   +15
Impacted Files Coverage Δ
src/index.js 100% <100%> (ø) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 9552c32...0aeee35. Read the comment docs.

this.promise = new Promise(
(resolve: (value?: R|Promise<R>) => void,
reject: (reason?: Error) => void) => {
this.resolve = resolve;

This comment was marked as spam.

This comment was marked as spam.

src/pool.ts Outdated
}

/**
* Reduces the number of operation for the provided client, potentially

This comment was marked as spam.

This comment was marked as spam.

test/pool.ts Outdated
@@ -0,0 +1,158 @@
/**
* Copyright 2017 Google Inc. All Rights Reserved.

This comment was marked as spam.

This comment was marked as spam.

test/pool.ts Outdated

const deferred = deferredPromises(4);

clientPool.run(() => deferred[0].promise);

This comment was marked as spam.

This comment was marked as spam.

test/pool.ts Outdated
completionPromises.push(clientPool.run(() => operationPromises[3].promise));
expect(clientPool.size).to.eq(2);

operationPromises[0].resolve();

This comment was marked as spam.

This comment was marked as spam.

@schmidt-sebastian
Copy link
Contributor Author

Mike, since you have more context on this client, do you mind taking a look at this as well?

Copy link
Contributor

@mikelehen mikelehen left a comment

Choose a reason for hiding this comment

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

I got 99 problems, but listening to 1 more problem isn't one of them anymore.

This looks good to me. Nice work with the auto-resizing pool stuff. I left a few nit / comment suggestions, but nothing major.

src/index.js Outdated
@@ -126,6 +132,12 @@ const CLOUD_RESOURCE_HEADER = 'google-cloud-resource-prefix';
*/
const MAX_REQUEST_RETRIES = 5;

/*!
* The maximum number of concurrent requests supported by a GAPIC client.

This comment was marked as spam.

This comment was marked as spam.

src/index.js Outdated
@@ -239,11 +251,11 @@ class Firestore {
});

/**
* A client pool to distribute requests over multiple GAPIC clients.

This comment was marked as spam.

This comment was marked as spam.

src/pool.ts Outdated
* concurrent operations.
*/
export class ClientPool<T> {
private activeClients: Map<T, number> = new Map();

This comment was marked as spam.

This comment was marked as spam.

src/pool.ts Outdated
this.activeClients.forEach((requestCount, client) => {
if (!selectedClient && requestCount < this.concurrentOperationLimit) {
selectedClient = client;
currentRequestCount = requestCount;

This comment was marked as spam.

This comment was marked as spam.

src/pool.ts Outdated
*/
private release(client: T): void {
let currentRequestCount = this.activeClients.get(client);
assert(currentRequestCount! > 0, 'Active client not found');

This comment was marked as spam.

This comment was marked as spam.

src/pool.ts Outdated
* removing it from the pool of active clients.
*/
private release(client: T): void {
let currentRequestCount = this.activeClients.get(client);

This comment was marked as spam.

This comment was marked as spam.

run<V>(op: (client: T) => Promise<V>): Promise<V> {
const client = this.acquire();

return op(client)

This comment was marked as spam.

This comment was marked as spam.


/**
* Deletes clients that are no longer executing operations. Keeps up to one
* idle client to reduce future initialization costs.

This comment was marked as spam.

This comment was marked as spam.

version = require('../../package.json').version;
} catch (e) {
version = require('../package.json').version;
}

This comment was marked as spam.

This comment was marked as spam.

@schmidt-sebastian schmidt-sebastian changed the base branch from initrefactor to master July 13, 2018 00:38
@schmidt-sebastian schmidt-sebastian force-pushed the 101listeners branch 2 times, most recently from 3ecd80b to e13acbe Compare July 13, 2018 00:46
@schmidt-sebastian schmidt-sebastian merged commit 4b853af into master Jul 13, 2018
@schmidt-sebastian schmidt-sebastian deleted the 101listeners branch July 24, 2018 04:26
wilhuff added a commit that referenced this pull request May 10, 2019
Previously _initializeStream returned a Promise that indicated that the
stream was "released", i.e. that it was was ready for attaching
listeners.

#256 Added pooled clients and changed the
callers of _initializeStream to reuse this promise such that when it was
resolved, the stream could be returned to the pool. This works when
listeners are short-lived, but fails when listeners run indefinitely.

This change arranges to release the clients back to the pool only after
the stream has completed, which allows an arbitrary number of indefinite
listens to run without problems.
wilhuff added a commit that referenced this pull request May 10, 2019
Previously _initializeStream returned a Promise that indicated that the
stream was "released", i.e. that it was was ready for attaching
listeners.

#256 Added pooled clients and changed the
callers of _initializeStream to reuse this promise such that when it was
resolved, the stream could be returned to the pool. This works when
listeners are short-lived, but fails when listeners run indefinitely.

This change arranges to release the clients back to the pool only after
the stream has completed, which allows an arbitrary number of indefinite
listens to run without problems.
wilhuff added a commit that referenced this pull request May 10, 2019
Fixes firebase/firebase-admin-node#499

Previously _initializeStream returned a Promise that indicated that the
stream was "released", i.e. that it was was ready for attaching
listeners.

#256 Added pooled clients and changed the
callers of _initializeStream to reuse this promise such that when it was
resolved, the stream could be returned to the pool. This works when
listeners are short-lived, but fails when listeners run indefinitely.

This change arranges to release the clients back to the pool only after
the stream has completed, which allows an arbitrary number of indefinite
listens to run without problems.

This turns out to be fiendishly difficult to test given the current structure
of the code. A second pass at this that reformulates this as just another
stream that composes with the others would make this easier to understand and
test. For now, this fix unblocks the customers waiting on the referenced issue.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cla: yes This human has signed the Contributor License Agreement.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants