From 7c67a5a0f93f9d506ee4010e2837288457fc2c1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karol=20S=C3=B3jko?= Date: Thu, 28 Dec 2023 15:21:40 +0100 Subject: [PATCH] fix: retry grpc calls upon service unavailable response (#1011) * fix: retry grpc calls upon service unavailable response * fix: retry grpc calls for session verification --- .pnp.cjs | 14 +-- ...c-js-npm-1.9.13-33f9b49e10-c52150053c.zip} | Bin 559041 -> 559079 bytes packages/api-gateway/package.json | 2 +- .../src/Service/gRPC/GRPCServiceProxy.ts | 81 ++++++++++++++++-- packages/auth/package.json | 2 +- packages/grpc/package.json | 2 +- packages/syncing-server/package.json | 2 +- yarn.lock | 16 ++-- 8 files changed, 92 insertions(+), 27 deletions(-) rename .yarn/cache/{@grpc-grpc-js-npm-1.9.12-cb97be6754-fe13b04844.zip => @grpc-grpc-js-npm-1.9.13-33f9b49e10-c52150053c.zip} (92%) diff --git a/.pnp.cjs b/.pnp.cjs index 80e09e95b..ccf0ecdee 100755 --- a/.pnp.cjs +++ b/.pnp.cjs @@ -2190,10 +2190,10 @@ const RAW_RUNTIME_STATE = }]\ ]],\ ["@grpc/grpc-js", [\ - ["npm:1.9.12", {\ - "packageLocation": "./.yarn/cache/@grpc-grpc-js-npm-1.9.12-cb97be6754-fe13b04844.zip/node_modules/@grpc/grpc-js/",\ + ["npm:1.9.13", {\ + "packageLocation": "./.yarn/cache/@grpc-grpc-js-npm-1.9.13-33f9b49e10-c52150053c.zip/node_modules/@grpc/grpc-js/",\ "packageDependencies": [\ - ["@grpc/grpc-js", "npm:1.9.12"],\ + ["@grpc/grpc-js", "npm:1.9.13"],\ ["@grpc/proto-loader", "npm:0.7.10"],\ ["@types/node", "npm:20.2.5"]\ ],\ @@ -5532,7 +5532,7 @@ const RAW_RUNTIME_STATE = "packageLocation": "./packages/api-gateway/",\ "packageDependencies": [\ ["@standardnotes/api-gateway", "workspace:packages/api-gateway"],\ - ["@grpc/grpc-js", "npm:1.9.12"],\ + ["@grpc/grpc-js", "npm:1.9.13"],\ ["@standardnotes/domain-core", "workspace:packages/domain-core"],\ ["@standardnotes/domain-events", "workspace:packages/domain-events"],\ ["@standardnotes/domain-events-infra", "workspace:packages/domain-events-infra"],\ @@ -5582,7 +5582,7 @@ const RAW_RUNTIME_STATE = ["@aws-sdk/client-sqs", "npm:3.462.0"],\ ["@cbor-extract/cbor-extract-linux-arm64", "npm:2.1.1"],\ ["@cbor-extract/cbor-extract-linux-x64", "npm:2.1.1"],\ - ["@grpc/grpc-js", "npm:1.9.12"],\ + ["@grpc/grpc-js", "npm:1.9.13"],\ ["@simplewebauthn/server", "npm:8.1.1"],\ ["@simplewebauthn/typescript-types", "npm:8.0.0"],\ ["@standardnotes/api", "npm:1.26.26"],\ @@ -5809,7 +5809,7 @@ const RAW_RUNTIME_STATE = "packageLocation": "./packages/grpc/",\ "packageDependencies": [\ ["@standardnotes/grpc", "workspace:packages/grpc"],\ - ["@grpc/grpc-js", "npm:1.9.12"],\ + ["@grpc/grpc-js", "npm:1.9.13"],\ ["@types/google-protobuf", "npm:3.15.10"],\ ["google-protobuf", "npm:3.21.2"],\ ["grpc-tools", "npm:1.12.4"],\ @@ -6082,7 +6082,7 @@ const RAW_RUNTIME_STATE = ["@aws-sdk/client-s3", "npm:3.462.0"],\ ["@aws-sdk/client-sns", "npm:3.462.0"],\ ["@aws-sdk/client-sqs", "npm:3.462.0"],\ - ["@grpc/grpc-js", "npm:1.9.12"],\ + ["@grpc/grpc-js", "npm:1.9.13"],\ ["@standardnotes/api", "npm:1.26.26"],\ ["@standardnotes/common", "workspace:packages/common"],\ ["@standardnotes/domain-core", "workspace:packages/domain-core"],\ diff --git a/.yarn/cache/@grpc-grpc-js-npm-1.9.12-cb97be6754-fe13b04844.zip b/.yarn/cache/@grpc-grpc-js-npm-1.9.13-33f9b49e10-c52150053c.zip similarity index 92% rename from .yarn/cache/@grpc-grpc-js-npm-1.9.12-cb97be6754-fe13b04844.zip rename to .yarn/cache/@grpc-grpc-js-npm-1.9.13-33f9b49e10-c52150053c.zip index c9dcb7b75eacedb4f86ca4b2a90130d0103a318e..3f5828fca3681b92aa9886fbf16d7e87e8cb4133 100644 GIT binary patch delta 22637 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 delta 22485 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 GWAuLo7>h#y diff --git a/packages/api-gateway/package.json b/packages/api-gateway/package.json index ae1b14f9d..826a8fffb 100644 --- a/packages/api-gateway/package.json +++ b/packages/api-gateway/package.json @@ -31,7 +31,7 @@ "start": "yarn node dist/bin/server.js" }, "dependencies": { - "@grpc/grpc-js": "^1.9.12", + "@grpc/grpc-js": "^1.9.13", "@standardnotes/domain-core": "workspace:^", "@standardnotes/domain-events": "workspace:*", "@standardnotes/domain-events-infra": "workspace:*", diff --git a/packages/api-gateway/src/Service/gRPC/GRPCServiceProxy.ts b/packages/api-gateway/src/Service/gRPC/GRPCServiceProxy.ts index 0beffce35..6fa6112f0 100644 --- a/packages/api-gateway/src/Service/gRPC/GRPCServiceProxy.ts +++ b/packages/api-gateway/src/Service/gRPC/GRPCServiceProxy.ts @@ -8,6 +8,7 @@ import * as grpc from '@grpc/grpc-js' import { CrossServiceTokenCacheInterface } from '../Cache/CrossServiceTokenCacheInterface' import { ServiceProxyInterface } from '../Proxy/ServiceProxyInterface' import { GRPCSyncingServerServiceProxy } from './GRPCSyncingServerServiceProxy' +import { Status } from '@grpc/grpc-js/build/src/constants' export class GRPCServiceProxy implements ServiceProxyInterface { constructor( @@ -27,11 +28,14 @@ export class GRPCServiceProxy implements ServiceProxyInterface { private gRPCSyncingServerServiceProxy: GRPCSyncingServerServiceProxy, ) {} - async validateSession(headers: { - authorization: string - sharedVaultOwnerContext?: string - }): Promise<{ status: number; data: unknown; headers: { contentType: string } }> { - return new Promise((resolve, reject) => { + async validateSession( + headers: { + authorization: string + sharedVaultOwnerContext?: string + }, + retryAttempt?: number, + ): Promise<{ status: number; data: unknown; headers: { contentType: string } }> { + const promise = new Promise((resolve, reject) => { try { const request = new AuthorizationHeader() request.setBearerToken(headers.authorization) @@ -80,6 +84,32 @@ export class GRPCServiceProxy implements ServiceProxyInterface { return reject(error) } }) + + try { + const result = await promise + + if (retryAttempt) { + this.logger.info(`Request to Auth Server succeeded after ${retryAttempt} retries`) + } + + return result as { status: number; data: unknown; headers: { contentType: string } } + } catch (error) { + const requestDidNotMakeIt = + 'code' in (error as Record) && (error as Record).code === Status.UNAVAILABLE + + const tooManyRetryAttempts = retryAttempt && retryAttempt > 2 + if (!tooManyRetryAttempts && requestDidNotMakeIt) { + await this.timer.sleep(50) + + const nextRetryAttempt = retryAttempt ? retryAttempt + 1 : 1 + + this.logger.info(`Retrying request to Auth Server for the ${nextRetryAttempt} time`) + + return this.validateSession(headers, nextRetryAttempt) + } + + throw error + } } async callSyncingServer( @@ -92,6 +122,21 @@ export class GRPCServiceProxy implements ServiceProxyInterface { payload !== undefined && typeof payload !== 'string' && 'api' in payload && payload.api === '20200115' if (requestIsUsingLatestApiVersions && endpoint === 'items/sync') { + await this.callSyncingServerGRPC(request, response, payload) + + return + } + + await this.callServer(this.syncingServerJsUrl, request, response, endpoint, payload) + } + + private async callSyncingServerGRPC( + request: Request, + response: Response, + payload?: Record | string, + retryAttempt?: number, + ): Promise { + try { const result = await this.gRPCSyncingServerServiceProxy.sync(request, response, payload) response.status(result.status).send({ @@ -107,10 +152,30 @@ export class GRPCServiceProxy implements ServiceProxyInterface { data: result.data, }) - return - } + if (retryAttempt) { + this.logger.info(`Request to Syncing Server succeeded after ${retryAttempt} retries`, { + userId: response.locals.user ? response.locals.user.uuid : undefined, + }) + } + } catch (error) { + const requestDidNotMakeIt = + 'code' in (error as Record) && (error as Record).code === Status.UNAVAILABLE - await this.callServer(this.syncingServerJsUrl, request, response, endpoint, payload) + const tooManyRetryAttempts = retryAttempt && retryAttempt > 2 + if (!tooManyRetryAttempts && requestDidNotMakeIt) { + await this.timer.sleep(50) + + const nextRetryAttempt = retryAttempt ? retryAttempt + 1 : 1 + + this.logger.info(`Retrying request to Syncing Server for the ${nextRetryAttempt} time`, { + userId: response.locals.user ? response.locals.user.uuid : undefined, + }) + + return this.callSyncingServerGRPC(request, response, payload, nextRetryAttempt) + } + + throw error + } } async callRevisionsServer( diff --git a/packages/auth/package.json b/packages/auth/package.json index c7eaf98a8..4b28a431e 100644 --- a/packages/auth/package.json +++ b/packages/auth/package.json @@ -43,7 +43,7 @@ "@aws-sdk/client-sqs": "^3.462.0", "@cbor-extract/cbor-extract-linux-arm64": "^2.1.1", "@cbor-extract/cbor-extract-linux-x64": "^2.1.1", - "@grpc/grpc-js": "^1.9.12", + "@grpc/grpc-js": "^1.9.13", "@simplewebauthn/server": "^8.1.1", "@simplewebauthn/typescript-types": "^8.0.0", "@standardnotes/api": "^1.26.26", diff --git a/packages/grpc/package.json b/packages/grpc/package.json index 478239272..0951e6e78 100644 --- a/packages/grpc/package.json +++ b/packages/grpc/package.json @@ -27,7 +27,7 @@ "build": "tsc --build" }, "dependencies": { - "@grpc/grpc-js": "^1.9.12", + "@grpc/grpc-js": "^1.9.13", "google-protobuf": "^3.21.2" }, "devDependencies": { diff --git a/packages/syncing-server/package.json b/packages/syncing-server/package.json index bb29a9e73..a71c22f25 100644 --- a/packages/syncing-server/package.json +++ b/packages/syncing-server/package.json @@ -35,7 +35,7 @@ "@aws-sdk/client-s3": "^3.462.0", "@aws-sdk/client-sns": "^3.462.0", "@aws-sdk/client-sqs": "^3.462.0", - "@grpc/grpc-js": "^1.9.12", + "@grpc/grpc-js": "^1.9.13", "@standardnotes/api": "^1.26.26", "@standardnotes/common": "workspace:*", "@standardnotes/domain-core": "workspace:^", diff --git a/yarn.lock b/yarn.lock index 584d8d32b..15dff31a0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1583,13 +1583,13 @@ __metadata: languageName: node linkType: hard -"@grpc/grpc-js@npm:^1.9.12": - version: 1.9.12 - resolution: "@grpc/grpc-js@npm:1.9.12" +"@grpc/grpc-js@npm:^1.9.13": + version: 1.9.13 + resolution: "@grpc/grpc-js@npm:1.9.13" dependencies: "@grpc/proto-loader": "npm:^0.7.8" "@types/node": "npm:>=12.12.47" - checksum: fe13b04844b525ad860521589e2d640bb8cfeea46e3cb8e4eab537e0a4fcb04a033083c25d5c3cd4e061a6471c933f6f12e81dcc626acdcf68435e6e4a833a06 + checksum: c52150053ca3911bf9ec5012265aa754627aba9c60577ef07c594c5c22896e939ec0f656cc130a54a8651ea0ae23f385a4a48868fc71ff56dff54eeaec8b6912 languageName: node linkType: hard @@ -4084,7 +4084,7 @@ __metadata: version: 0.0.0-use.local resolution: "@standardnotes/api-gateway@workspace:packages/api-gateway" dependencies: - "@grpc/grpc-js": "npm:^1.9.12" + "@grpc/grpc-js": "npm:^1.9.13" "@standardnotes/domain-core": "workspace:^" "@standardnotes/domain-events": "workspace:*" "@standardnotes/domain-events-infra": "workspace:*" @@ -4147,7 +4147,7 @@ __metadata: "@aws-sdk/client-sqs": "npm:^3.462.0" "@cbor-extract/cbor-extract-linux-arm64": "npm:^2.1.1" "@cbor-extract/cbor-extract-linux-x64": "npm:^2.1.1" - "@grpc/grpc-js": "npm:^1.9.12" + "@grpc/grpc-js": "npm:^1.9.13" "@simplewebauthn/server": "npm:^8.1.1" "@simplewebauthn/typescript-types": "npm:^8.0.0" "@standardnotes/api": "npm:^1.26.26" @@ -4361,7 +4361,7 @@ __metadata: version: 0.0.0-use.local resolution: "@standardnotes/grpc@workspace:packages/grpc" dependencies: - "@grpc/grpc-js": "npm:^1.9.12" + "@grpc/grpc-js": "npm:^1.9.13" "@types/google-protobuf": "npm:^3" google-protobuf: "npm:^3.21.2" grpc-tools: "npm:^1.12.4" @@ -4618,7 +4618,7 @@ __metadata: "@aws-sdk/client-s3": "npm:^3.462.0" "@aws-sdk/client-sns": "npm:^3.462.0" "@aws-sdk/client-sqs": "npm:^3.462.0" - "@grpc/grpc-js": "npm:^1.9.12" + "@grpc/grpc-js": "npm:^1.9.13" "@standardnotes/api": "npm:^1.26.26" "@standardnotes/common": "workspace:*" "@standardnotes/domain-core": "workspace:^"