Skip to content

Couple fixes for release of broken connections to the pool #368

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 2 commits into from
May 8, 2018
Merged
Show file tree
Hide file tree
Changes from all 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
12 changes: 6 additions & 6 deletions src/v1/internal/pool.js
Original file line number Diff line number Diff line change
Expand Up @@ -154,25 +154,25 @@ class Pool {
// key has been purged, don't put it back, just destroy the resource
this._destroy(resource);
}
resourceReleased(key, this._activeResourceCounts);

// check if there are any pending requests
const requests = this._acquireRequests[key];
if (requests) {
const pending = requests.shift();
const pending = requests[0];

if (pending) {
const resource = this._acquire(key);
if (resource) {
pending.resolve(resource);

return;
// managed to acquire a valid resource from the pool to satisfy the pending acquire request
resourceAcquired(key, this._activeResourceCounts); // increment the active counter
requests.shift(); // forget the pending request
pending.resolve(resource); // resolve the pending request with the acquired resource
}
} else {
delete this._acquireRequests[key];
}
}

resourceReleased(key, this._activeResourceCounts);
}
}

Expand Down
92 changes: 91 additions & 1 deletion test/internal/pool.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -522,16 +522,106 @@ describe('Pool', () => {
});
});

it('should resolve pending acquisition request when single invalid resource returned', done => {
const key = 'bolt://localhost:7687';
const acquisitionTimeout = 1000;
let counter = 0;

const pool = new Pool(
(url, release) => new Resource(url, counter++, release),
resource => {
},
resourceValidOnlyOnceValidationFunction,
new PoolConfig(1, acquisitionTimeout)
);

pool.acquire(key).then(resource1 => {
expect(resource1.id).toEqual(0);
expect(pool.activeResourceCount(key)).toEqual(1);

// release the resource before the acquisition timeout, it should be treated as invalid
setTimeout(() => {
expectNumberOfAcquisitionRequests(pool, key, 1);
resource1.close();
}, acquisitionTimeout / 2);

pool.acquire(key).then(resource2 => {
expect(resource2.id).toEqual(1);
expectNoPendingAcquisitionRequests(pool);
expect(pool.activeResourceCount(key)).toEqual(1);
done();
}).catch(error => {
done.fail(error);
});
});
});

it('should work fine when invalid resources released and acquisition attempt pending', done => {
const key = 'bolt://localhost:7687';
const acquisitionTimeout = 1000;
let counter = 0;

const pool = new Pool(
(url, release) => new Resource(url, counter++, release),
resource => {
},
resourceValidOnlyOnceValidationFunction,
new PoolConfig(2, acquisitionTimeout)
);

pool.acquire(key).then(resource1 => {
expect(resource1.id).toEqual(0);
expect(pool.activeResourceCount(key)).toEqual(1);

pool.acquire(key).then(resource2 => {
expect(resource2.id).toEqual(1);
expect(pool.activeResourceCount(key)).toEqual(2);

// release both resources before the acquisition timeout, they should be treated as invalid
setTimeout(() => {
expectNumberOfAcquisitionRequests(pool, key, 1);
resource1.close();
resource2.close();
}, acquisitionTimeout / 2);

pool.acquire(key).then(resource3 => {
expect(resource3.id).toEqual(2);
expectNoPendingAcquisitionRequests(pool);
expect(pool.activeResourceCount(key)).toEqual(1);
done();
}).catch(error => {
done.fail(error);
});
});
});
});

});

function expectNoPendingAcquisitionRequests(pool) {
expect(pool._acquireRequests).toEqual({});
const acquireRequests = pool._acquireRequests;
Object.values(acquireRequests).forEach(requests => {
if (Array.isArray(requests) && requests.length === 0) {
requests = undefined;
}
expect(requests).not.toBeDefined();
});
}

function expectNumberOfAcquisitionRequests(pool, key, expectedNumber) {
expect(pool._acquireRequests[key].length).toEqual(expectedNumber);
}

function resourceValidOnlyOnceValidationFunction(resource) {
// all resources are valid only once
if (resource.validatedOnce) {
return false;
} else {
resource.validatedOnce = true;
return true;
}
}

class Resource {

constructor(key, id, release) {
Expand Down