Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(7)

Side by Side Diff: web/inc/rpc/client.ts

Issue 2570963003: Revert of Rewrite LogDog log viewer app. (Closed)
Patch Set: Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « web/inc/luci-sleep-promise/promise.ts ('k') | web/inc/rpc/rpc-call.html » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 Copyright 2016 The LUCI Authors. All rights reserved.
3 Use of this source code is governed under the Apache License, Version 2.0
4 that can be found in the LICENSE file.
5 */
6
7 import * as luci_sleep_promise from "luci-sleep-promise/promise";
8
9 export namespace luci_rpc {
10
11 interface PolymerClient {
12 service: string;
13 method: string;
14 request: any;
15
16 call(): {
17 completes: Promise<any>,
18 };
19 }
20
21 export class Client {
22 transientRetry: Retry = new Retry(new RetryIterator(10, 500, null));
23 private pc: PolymerClient;
24
25 constructor(pc: any) {
26 this.pc = pc as PolymerClient;
27 }
28
29 /** Call invokes the specified service's method, returning a Promise. */
30 call<T, R>(service: string, method: string, request?: T): Promise<R> {
31 this.pc.service = service;
32 this.pc.method = method;
33 this.pc.request = request;
34
35 let transientRetry = this.transientRetry.iterator();
36 let doCall = (): Promise<R> => {
37 let callPromise: Promise<R> = this.pc.call().completes;
38 return callPromise.then( (resp: any) => {
39 return resp.response;
40 }).catch( (err: Error) => {
41 // Is this a transient error?
42 if ( isTransientError(err) ) {
43 let delay = transientRetry.next();
44 if ( delay ) {
45 console.warn(
46 `Transient error calling ${service}.${method} with params:`,
47 request, `:`, err, `; retrying after ${delay}ms.`);
48 return luci_sleep_promise.sleep(delay).then( () => {
49 return doCall();
50 });
51 }
52 }
53
54 // Non-transient, throw the error.
55 throw err;
56 });
57 };
58 return doCall();
59 }
60 }
61
62 /** gRPC Codes */
63 export enum Code {
64 OK = 0,
65 CANCELED = 1,
66 UNKNOWN = 2,
67 INVALID_ARGUMENT = 3,
68 DEADLINE_EXCEEDED = 4,
69 NOT_FOUND = 5,
70 ALREADY_EXISTS = 6,
71 PERMISSION_DENIED = 7,
72 UNAUTHENTICATED = 16,
73 RESOURCE_EXHAUSTED = 8,
74 FAILED_PRECONDITION = 9,
75 ABORTED = 10,
76 OUT_OF_RANGE = 11,
77 UNIMPLEMENTED = 12,
78 INTERNAL = 13,
79 UNAVAILABLE = 14,
80 DATA_LOSS = 15
81 }
82
83 export class GrpcError extends Error {
84 constructor(readonly code: Code, readonly description?: string) {
85 super("code = " + code + ", desc = " + description);
86 }
87
88 /**
89 * Converts the supplied Error into a GrpcError if its name is
90 * "GrpcError". This merges between the non-Typescript RPC code and this
91 * error type.
92 */
93 static convert(err: Error): GrpcError | null {
94 if ( err.name === 'GrpcError' ) {
95 let aerr = err as GrpcError;
96 return new GrpcError(aerr.code, aerr.description);
97 }
98 return null;
99 }
100
101 /** Returns true if the error is considered transient. */
102 get transient(): boolean {
103 switch ( this.code ) {
104 case Code.INTERNAL:
105 case Code.UNAVAILABLE:
106 case Code.RESOURCE_EXHAUSTED:
107 return true;
108
109 default:
110 return false;
111 }
112 }
113 }
114
115 export class HttpError extends Error {
116 constructor(readonly code: Code, readonly description?: string) {
117 super("code = " + code + ", desc = " + description);
118 }
119
120 /**
121 * Converts the supplied Error into a HttpError if its name is
122 * "HttpError". This merges between the non-Typescript RPC code and this
123 * error type.
124 */
125 static convert(err: Error): HttpError | null {
126 if ( err.name === 'HttpError' ) {
127 let aerr = err as HttpError;
128 return new HttpError(aerr.code, aerr.description);
129 }
130 return null;
131 }
132
133 /** Returns true if the error is considered transient. */
134 get transient(): boolean { return ( this.code >= 500 ); }
135 }
136
137 export function isTransientError(err: Error): boolean {
138 let grpc = GrpcError.convert(err);
139 if ( grpc ) {
140 return grpc.transient;
141 }
142
143 // Is this an HTTP Error?
144 let http = HttpError.convert(err);
145 if ( http ) {
146 return http.transient;
147 }
148
149 // Unknown error.
150 return false;
151 }
152
153 export class RetryIterator {
154 private retries: number | null;
155 private delay: number;
156 private maxDelay: number | null;
157
158 constructor(retries: number | null, delay: number,
159 maxDelay: number | null) {
160
161 this.retries = retries;
162 this.delay = delay;
163 this.maxDelay = maxDelay;
164 }
165
166 clone(): RetryIterator {
167 return new RetryIterator(this.retries, this.delay, this.maxDelay);
168 }
169
170 next(): number | null {
171 if ( this.retries !== null ) {
172 if ( this.retries <= 0 ) {
173 // No more retries remaining.
174 return null;
175 }
176 this.retries--;
177 }
178
179 let delay = this.delay;
180 this.delay *= 2;
181 if ( this.maxDelay !== null && this.delay > this.maxDelay ) {
182 this.delay = this.maxDelay;
183 }
184 return delay;
185 }
186 }
187
188 export class Retry {
189 private base: RetryIterator;
190
191 constructor(base: RetryIterator) {
192 this.base = base;
193 }
194
195 iterator(): RetryIterator {
196 return this.base.clone();
197 }
198 }
199
200 }
OLDNEW
« no previous file with comments | « web/inc/luci-sleep-promise/promise.ts ('k') | web/inc/rpc/rpc-call.html » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698