Skip to content

Commit

Permalink
feat: Add Koa Server Request Timeout (hashgraph#2504)
Browse files Browse the repository at this point in the history
* Add Koa Server Request Timeout

Signed-off-by: Nana Essilfie-Conduah <nana@swirldslabs.com>

* fix: Added test and documentation to the server request timeout setting.

Signed-off-by: ebadiere <ebadiere@gmail.com>

fix: Added doc updated.

Signed-off-by: ebadiere <ebadiere@gmail.com>

fix: Bumped timeout to 60 seconds.

Signed-off-by: ebadiere <ebadiere@gmail.com>

fix: removed only.

Signed-off-by: ebadiere <ebadiere@gmail.com>

fix: Added empty line.

Signed-off-by: ebadiere <ebadiere@gmail.com>

Update packages/server/src/index.ts

Co-authored-by: Logan Nguyen <logan.nguyen@swirldslabs.com>
Signed-off-by: Eric Badiere <ebadiere@gmail.com>

fix: Applied feedback

Signed-off-by: ebadiere <ebadiere@gmail.com>

fix: Added back the chai.

Signed-off-by: ebadiere <ebadiere@gmail.com>

fix: Restored the chai exclude

Signed-off-by: ebadiere <ebadiere@gmail.com>

fix: Removed the async in the sendJsonRpcRequestWithDelay

Signed-off-by: ebadiere <ebadiere@gmail.com>

fix: Reduced the timeout to allow tests to finish.

Signed-off-by: ebadiere <ebadiere@gmail.com>

fix: Moved timeout test to rateLimiter.

Signed-off-by: ebadiere <ebadiere@gmail.com>

fix: Removed comma after LIMIT_DURATION

Signed-off-by: ebadiere <ebadiere@gmail.com>

fix: Bumped up the timeout delay to ensure it works in CI.

Signed-off-by: ebadiere <ebadiere@gmail.com>

fix: Testing in CI.  Removed the .only

Signed-off-by: ebadiere <ebadiere@gmail.com>

fix: Adjusted the test delay.

Signed-off-by: ebadiere <ebadiere@gmail.com>

fix: Added error details.

Signed-off-by: ebadiere <ebadiere@gmail.com>

fix: Added more debug info.

Signed-off-by: ebadiere <ebadiere@gmail.com>

fix: Added delay for linux.  Debugging in CI.

Signed-off-by: ebadiere <ebadiere@gmail.com>

fix: Debugging in CI.  Setting test timeout

Signed-off-by: ebadiere <ebadiere@gmail.com>

fix: Debugging in CI.  Nested promise.

Signed-off-by: ebadiere <ebadiere@gmail.com>

fix: Including delay in testfile.  Debugging CI.

Signed-off-by: ebadiere <ebadiere@gmail.com>

fix: Debugging in CIfix: Debugging in CI.  Updated package-log.
Signed-off-by: ebadiere <ebadiere@gmail.com>

fix: Extracted setting logic to util function to be used in server startup and test framework

Signed-off-by: ebadiere <ebadiere@gmail.com>

fix:  Bumped up the timeout for tests on local node.

Signed-off-by: ebadiere <ebadiere@gmail.com>

* fix: Moved into its own CI job.

Signed-off-by: ebadiere <ebadiere@gmail.com>

* fix: Cleanup

Signed-off-by: ebadiere <ebadiere@gmail.com>

* fix: Clean up.

Signed-off-by: ebadiere <ebadiere@gmail.com>

---------

Signed-off-by: Nana Essilfie-Conduah <nana@swirldslabs.com>
Signed-off-by: ebadiere <ebadiere@gmail.com>
Co-authored-by: ebadiere <ebadiere@gmail.com>
  • Loading branch information
Nana-EC and ebadiere authored May 28, 2024
1 parent 2ee70c7 commit 53e5e4b
Show file tree
Hide file tree
Showing 13 changed files with 148 additions and 2 deletions.
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:
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);
}
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) => {
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

0 comments on commit 53e5e4b

Please sign in to comment.