Skip to content
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

feat: Add Koa Server Request Timeout #2504

Merged
merged 6 commits into from
May 28, 2024
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
6 changes: 6 additions & 0 deletions .github/workflows/acceptance.yml
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,12 @@ jobs:
with:
testfilter: cache-service

server-config:
quiet-node marked this conversation as resolved.
Show resolved Hide resolved
name: Server Config
uses: ./.github/workflows/acceptance-workflow.yml
with:
testfilter: serverconfig

publish_results:
name: Publish Results
if: ${{ !cancelled() }}
Expand Down
1 change: 1 addition & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ Unless you need to set a non-default value, it is recommended to only populate o
| `RATE_LIMIT_DISABLED` | "false" | Flag to disable IP based rate limiting. |
| `REQUEST_ID_IS_OPTIONAL` | "" | Flag to set it the JSON RPC request id field in the body should be optional. Note, this breaks the API spec and is not advised and is provided for test purposes only where some wallets may be non compliant |
| `SERVER_PORT` | "7546" | The RPC server port number to listen for requests on. Currently a static value defaulting to 7546. See [#955](https://github.com/hashgraph/hedera-json-rpc-relay/issues/955) |
| `SERVER_REQUEST_TIMEOUT_MS`| "60000" | The time of inactivity allowed before a timeout is triggered and the socket is closed. See [NodeJs Server Timeout](https://nodejs.org/api/http.html#serversettimeoutmsecs-callback) |

## Relay

Expand Down
2 changes: 2 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
"acceptancetest:precompile-calls": "ts-mocha packages/server/tests/acceptance/index.spec.ts -g '@precompile-calls' --exit",
"acceptancetest:cache-service": "ts-mocha packages/server/tests/acceptance/index.spec.ts -g '@cache-service' --exit",
"acceptancetest:rpc_api_schema_conformity": "ts-mocha packages/server/tests/acceptance/index.spec.ts -g '@api-conformity' --exit",
"acceptancetest:serverconfig": "ts-mocha packages/server/tests/acceptance/index.spec.ts -g '@server-config' --exit",
"build": "npx lerna run build",
"build-and-test": "npx lerna run build && npx lerna run test",
"build:docker": "docker build . -t ${npm_package_name}",
Expand Down
6 changes: 5 additions & 1 deletion packages/server/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,13 @@
*/

import app from './server';
import { setServerTimeout } from './koaJsonRpc/lib/utils'; // Import the 'setServerTimeout' function from the correct location

async function main() {
await app.listen({ port: process.env.SERVER_PORT || 7546 });
const server = await app.listen({ port: process.env.SERVER_PORT || 7546 });

// set request timeout to ensure sockets are closed after specified time of inactivity
setServerTimeout(server);
}

main();
26 changes: 26 additions & 0 deletions packages/server/src/koaJsonRpc/lib/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*-
*
* Hedera JSON RPC Relay
*
* Copyright (C) 2024 Hedera Hashgraph, LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/

import type { Server } from 'http';

export function setServerTimeout(server: Server): void {
const requestTimeoutMs = parseInt(process.env.SERVER_REQUEST_TIMEOUT_MS ?? '60000');
server.setTimeout(requestTimeoutMs);
quiet-node marked this conversation as resolved.
Show resolved Hide resolved
}
2 changes: 2 additions & 0 deletions packages/server/tests/acceptance/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import constants from '@hashgraph/json-rpc-relay/dist/lib/constants';
// Utils and types
import { Utils } from '../helpers/utils';
import { AliasAccount } from '../types/AliasAccount';
import { setServerTimeout } from '../../src/koaJsonRpc/lib/utils';

chai.use(chaiAsPromised);
dotenv.config({ path: path.resolve(__dirname, '../../../.env') });
Expand Down Expand Up @@ -185,6 +186,7 @@ describe('RPC Server Acceptance Tests', function () {

logger.info(`Start relay on port ${constants.RELAY_PORT}`);
relayServer = app.listen({ port: constants.RELAY_PORT });
setServerTimeout(relayServer);

if (process.env.TEST_WS_SERVER === 'true') {
logger.info(`Start ws-server on port ${constants.WEB_SOCKET_PORT}`);
Expand Down
2 changes: 1 addition & 1 deletion packages/server/tests/acceptance/rateLimiter.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
*
* Hedera JSON RPC Relay
*
* Copyright (C) 2023 Hedera Hashgraph, LLC
* Copyright (C) 2023-2024 Hedera Hashgraph, LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down
41 changes: 41 additions & 0 deletions packages/server/tests/acceptance/serverConfig.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*-
*
* Hedera JSON RPC Relay
*
* Copyright (C) 2024 Hedera Hashgraph, LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
import { expect } from 'chai';
import { Utils } from '../helpers/utils';

describe('@server-config Server Configuration Options Coverage', function () {
describe('Koa Server Timeout', () => {
it('should timeout a request after the specified time', async () => {
const requestTimeoutMs: number = parseInt(process.env.SERVER_REQUEST_TIMEOUT_MS || '3000');
const host = 'localhost';
const port = parseInt(process.env.SERVER_PORT || '7546');
const method = 'eth_blockNumber';
const params: any[] = [];

try {
await Utils.sendJsonRpcRequestWithDelay(host, port, method, params, requestTimeoutMs + 1000);
throw new Error('Request did not timeout as expected'); // Force the test to fail if the request does not time out
} catch (err) {
expect(err.code).to.equal('ECONNRESET');
expect(err.message).to.equal('socket hang up');
}
});
});
});
60 changes: 60 additions & 0 deletions packages/server/tests/helpers/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import RelayCall from '../../tests/helpers/constants';
import { AccountId, KeyList, PrivateKey } from '@hashgraph/sdk';
import { AliasAccount } from '../types/AliasAccount';
import ServicesClient from '../clients/servicesClient';
import http from 'http';

export class Utils {
/**
Expand Down Expand Up @@ -308,4 +309,63 @@ export class Utils {
}
return accounts;
}

static sendJsonRpcRequestWithDelay(
host: string,
port: number,
method: string,
params: any[],
delayMs: number,
): Promise<any> {
const requestData = JSON.stringify({
jsonrpc: '2.0',
method: method,
params: params,
id: 1,
});

const options = {
hostname: host,
port: port,
path: '/',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(requestData),
},
timeout: delayMs,
};

return new Promise((resolve, reject) => {
// setup the request
const req = http.request(options, (res) => {
quiet-node marked this conversation as resolved.
Show resolved Hide resolved
let data = '';

res.on('data', (chunk) => {
data += chunk;
});

res.on('end', () => {
resolve(JSON.parse(data));
});
});

// handle request errors for testing purposes
req.on('timeout', () => {
req.destroy();
reject(new Error(`Request timed out after ${delayMs}ms`));
});

req.on('error', (err) => {
reject(err);
});

// Introduce a delay with inactivity, before sending the request
setTimeout(async () => {
req.write(requestData);
req.end();
await new Promise((r) => setTimeout(r, delayMs + 1000));
}, delayMs);
});
}
}
1 change: 1 addition & 0 deletions packages/server/tests/localAcceptance.env
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,4 @@ TEST_GAS_PRICE_DEVIATION=0.2
WS_NEW_HEADS_ENABLED=false
INITIAL_BALANCE='5000000000'
LIMIT_DURATION=90000
SERVER_REQUEST_TIMEOUT_MS=60000
1 change: 1 addition & 0 deletions packages/server/tests/previewnetAcceptance.env
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@ FILTER_API_ENABLED=true
DEBUG_API_ENABLED=true
TEST_GAS_PRICE_DEVIATION=0.2
WS_NEW_HEADS_ENABLED=true
SERVER_REQUEST_TIMEOUT_MS=60000

1 change: 1 addition & 0 deletions packages/server/tests/testnetAcceptance.env
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ SUBSCRIPTIONS_ENABLED=true
FILTER_API_ENABLED=true
DEBUG_API_ENABLED=true
TEST_GAS_PRICE_DEVIATION=0.2
SERVER_REQUEST_TIMEOUT_MS=60000
Loading