Skip to content

Commit

Permalink
Support rpc timeout (#138)
Browse files Browse the repository at this point in the history
  • Loading branch information
timostamm authored Aug 4, 2021
1 parent 3970204 commit e357ed9
Show file tree
Hide file tree
Showing 11 changed files with 42 additions and 28 deletions.
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
### unreleased changes

none
Breaking changes:

- `RpcOptions` takes a `timeout` property now. `deadline` property
has been removed. See #138 for details.


### v2.0.0-alpha.29
Expand Down
7 changes: 3 additions & 4 deletions MANUAL.md
Original file line number Diff line number Diff line change
Expand Up @@ -1409,10 +1409,9 @@ The options:
If a key ends with `-bin`, it should contain binary data in base64
encoding, allowing you to send serialized messages.
- `deadline: Date | number`
Deadline for the call. Can be a specific date or a
timeout in milliseconds.
- `timeout: Date | number`
Timeout for the call in milliseconds.
If a Date object is given, it is used as a deadline.
- `interceptors: RpcInterceptor[]`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ <h5>GrpcWebOptions:</h5>
</div>
<div class="large-3 medium-4 cell">
<label>Deadline (milliseconds)</label>
<input name="options_deadline" type="number" min="0" step="100" [(ngModel)]="options.deadline"
<input name="options_timeout" type="number" min="0" step="100" [(ngModel)]="options.timeout"
placeholder="deadline"/>
</div>
<div class="large-3 medium-4 cell">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export class GrpcwebServerStreamingComponent {

readonly options: GrpcWebOptions = {
baseUrl: 'http://localhost:5080',
deadline: Date.now() + 2000,
timeout: Date.now() + 2000,
format: 'binary',

// simple example for how to add auth headers to each request
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ <h5>GrpcWebOptions:</h5>
</div>
<div class="large-3 medium-4 cell">
<label>Deadline (milliseconds)</label>
<input name="options_deadline" type="number" min="0" step="100" [(ngModel)]="options.deadline"
<input name="options_timeout" type="number" min="0" step="100" [(ngModel)]="options.timeout"
placeholder="deadline"/>
</div>
<div class="large-3 medium-4 cell">
Expand Down
2 changes: 1 addition & 1 deletion packages/example-node-grpcweb-transport-client/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ async function callServerStream(client: IExampleServiceClient) {
const headers = await call.headers;
console.log("got response headers: ", headers)

for await (let response of call.response) {
for await (let response of call.responses) {
console.log("got response message: ", response)
}

Expand Down
10 changes: 7 additions & 3 deletions packages/grpc-transport/src/grpc-transport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,13 @@ export class GrpcTransport implements RpcTransport {
if (options.callOptions) {
return options.callOptions;
}
return {
deadline: options.deadline
};
const co: CallOptions = {};
if (typeof options.timeout === "number") {
co.deadline = Date.now() + options.timeout;
} else if (options.timeout) {
co.deadline = options.timeout;
}
return co;
}

unary<I extends object, O extends object>(method: MethodInfo<I, O>, input: I, options: GrpcCallOptions): UnaryCall<I, O> {
Expand Down
26 changes: 17 additions & 9 deletions packages/grpcweb-transport/src/grpc-web-format.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {GrpcStatusCode} from "./goog-grpc-status-code";
/**
* Create fetch API headers for a grpc-web request.
*/
export function createGrpcWebRequestHeader(headers: Headers, format: GrpcWebFormat, deadline: Date | number | undefined, meta?: RpcMetadata, userAgent?: string): Headers {
export function createGrpcWebRequestHeader(headers: Headers, format: GrpcWebFormat, timeout: Date | number | undefined, meta?: RpcMetadata, userAgent?: string): Headers {
// add meta as headers
if (meta) {
for (let [k, v] of Object.entries(meta)) {
Expand All @@ -28,15 +28,23 @@ export function createGrpcWebRequestHeader(headers: Headers, format: GrpcWebForm
headers.set('X-Grpc-Web', "1");
if (userAgent)
headers.set("X-User-Agent", userAgent);
if (deadline) {
let ts = typeof deadline == "number" ? deadline : deadline.getTime();
let timeout = ts - Date.now();
headers.set('grpc-timeout', timeout + 'm');

if (typeof timeout === "number") {
if (timeout <= 0) {
// we raise an error ourselves because header "grpc-timeout" must be a positive integer
throw new RpcError(`timeout ${timeout} ms exceeded`, GrpcStatusCode[GrpcStatusCode.DEADLINE_EXCEEDED]);
}
headers.set('grpc-timeout', `${timeout}m`);
} else if (timeout) {
const deadline = timeout.getTime();
const now = Date.now();
if (deadline <= now) {
// we raise an error ourselves because header "grpc-timeout" must be a positive integer
throw new RpcError(`deadline ${timeout} exceeded`, GrpcStatusCode[GrpcStatusCode.DEADLINE_EXCEEDED]);
}
headers.set('grpc-timeout', `${deadline - now}m`);
}
// let timeout = typeof deadline == "number" ? deadline : deadline instanceof Date ? (deadline.getTime() - Date.now()) : 0;
// if (timeout > 0) {
// headers.set('grpc-timeout', timeout + 'm');
// }

return headers;
}

Expand Down
4 changes: 2 additions & 2 deletions packages/grpcweb-transport/src/grpc-web-transport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ export class GrpcWebFetchTransport implements RpcTransport {
globalThis.fetch(url, {
...fetchInit,
method: 'POST',
headers: createGrpcWebRequestHeader(new globalThis.Headers(), format, opt.deadline, opt.meta),
headers: createGrpcWebRequestHeader(new globalThis.Headers(), format, opt.timeout, opt.meta),
body: createGrpcWebRequestBody(inputBytes, format),
signal: options.abort ?? null // node-fetch@3.0.0-beta.9 rejects `undefined`
})
Expand Down Expand Up @@ -197,7 +197,7 @@ export class GrpcWebFetchTransport implements RpcTransport {
globalThis.fetch(url, {
...fetchInit,
method: 'POST',
headers: createGrpcWebRequestHeader(new globalThis.Headers(), format, opt.deadline, opt.meta),
headers: createGrpcWebRequestHeader(new globalThis.Headers(), format, opt.timeout, opt.meta),
body: createGrpcWebRequestBody(inputBytes, format),
signal: options.abort ?? null // node-fetch@3.0.0-beta.9 rejects `undefined`
})
Expand Down
4 changes: 2 additions & 2 deletions packages/runtime-rpc/spec/rpc-options.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import type {IMessageType} from "@protobuf-ts/runtime";
describe('mergeRpcOptions()', () => {

it('does not require seconds argument', function () {
let opt = mergeRpcOptions({deadline: 123}, undefined);
expect(opt).toEqual({deadline: 123});
let opt = mergeRpcOptions({timeout: 123}, undefined);
expect(opt).toEqual({timeout: 123});
});

it('merges interceptors', function () {
Expand Down
6 changes: 3 additions & 3 deletions packages/runtime-rpc/src/rpc-options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ export interface RpcOptions {
meta?: RpcMetadata;

/**
* Deadline for the call. Can be given as a Date object or a
* timestamp in milliseconds.
* Timeout for the call in milliseconds.
* If a Date object is given, it is used as a deadline.
*/
deadline?: Date | number;
timeout?: number | Date;

/**
* Interceptors can be used to manipulate request and response data.
Expand Down

0 comments on commit e357ed9

Please sign in to comment.