Skip to content

Commit

Permalink
fix: do not hang in LRO forever if API returned nothing (#436)
Browse files Browse the repository at this point in the history
* fix: do not hang in LRO forever if API returned nothing

* add test
  • Loading branch information
alexander-fenster authored and JustinBeckwith committed Mar 1, 2019
1 parent 1b8d268 commit fd1b4f0
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 0 deletions.
10 changes: 10 additions & 0 deletions src/longrunning.ts
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,16 @@ export class Operation extends EventEmitter {
setImmediate(emit, 'progress', metadata, rawResponse);
previousMetadataBytes = rawResponse!.metadata!.value;
}
// special case: some APIs fail to set either result or error
// but set done = true (e.g. speech with silent file).
// Don't hang forever in this case.
if (rawResponse!.done) {
const error = new GoogleError(
'Long running operation has finished but there was no result');
error.code = status.UNKNOWN;
setImmediate(emit, 'error', error);
return;
}
setTimeout(() => {
now = new Date();
delay = Math.min(delay * delayMult, maxDelay);
Expand Down
26 changes: 26 additions & 0 deletions test/longrunning.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,11 @@ const ERROR_OP = {
error: ERROR,
response: null,
};
const BAD_OP = {
name: OPERATION_NAME,
metadata: METADATA,
done: true,
};
const mockDecoder = val => {
return val.toString();
};
Expand Down Expand Up @@ -405,6 +410,27 @@ describe('longrunning', () => {
});
});

it('does not hang on invalid API response', done => {
const func = (argument, metadata, options, callback) => {
callback(null, PENDING_OP);
};
const client = mockOperationsClient({finalOperation: BAD_OP});
const apiCall = createApiCall(func, client);
apiCall()
.then(responses => {
const operation = responses[0];
const promise = operation.promise();
return promise;
})
.then(() => {
done(new Error('Should not get here.'));
})
.catch(error => {
expect(error).to.be.an('error');
done();
});
});

it('uses provided promise constructor', done => {
const client = mockOperationsClient();
const desc = new longrunning.LongrunningDescriptor(
Expand Down

0 comments on commit fd1b4f0

Please sign in to comment.