Restart hardhat JSON-RPC server from Node.js code - node.js

I'm using hardhat to forking the Ethereum mainnet and run some tests on it. In one terminal I start the server with:
npx hardhat node --fork https://eth-mainnet.alchemyapi.io/v2/$API_KEY
In another terminal I have Node.js code running. I need to periodically resync the network with mainnet. What is the best way to launch and terminate the hardhat server directly from the Node.js code?
I'm currently using the hardhat_reset command to force resync with the latest block, however this is not reliable enough, as the server code appears to enter bad state and transactions stop working.
const hre = require('hardhat');
async function test() {
const block = parseInt(await web3.eth.getBlockNumber());
await hre.network.provider.request({
method: "hardhat_reset",
params: [{forking: {
jsonRpcUrl: ALCHEMY_URL,
blockNumber: block,
}}]
});
}

Related

Blockchain listener app exited with code 0 docker

I have a simple websocket application running. I use ethers.js to listen to blockchain events, which uses websockets in the background. I connect to blockchain via Infura provider. When I dockerize the app and run the image, it continues to live for about 3-5 minutes, but then exits with code 0 without any errors or messages. When I run the application without dockerizing it from the terminal with simply npx ts-node src/index.ts command, then there is no problem and it keeps running forever.
It also logs ⛓️ [chain]: Started listening events in the docker logs so it is started successfully as well.
No event is captured from the listener and nothing happens, so it is not the case that something is executed and caused it to exit somehow. Also when I am able to make the transaction quick before it exits, it captures the event successfully and continues for some more time as well.
What could be reason behind this and what should I do to keep it running?
Here is my Dockerfile:
FROM node:alpine
WORKDIR /app
COPY package.json .
RUN npm install
COPY . .
CMD ["npx", "ts-node", "src/index.ts"]
Here is my index.ts:
import { listenContractEvents } from './events';
listenContractEvents()
.then(() => console.log('⛓️ [chain]: Started listening events'))
.catch(console.log);
Here is my events.ts:
const provider = new ethers.providers.WebSocketProvider(
`wss://goerli.infura.io/ws/v3/${process.env.INFURA_API_KEY}`
);
async function listenContractEvents() {
const contract = new ethers.Contract(
contractAddress,
contractAbi,
provider
);
let userList: User[] = await contract.getUserList();
contract.on('Register', async () => {
console.log('⛓️ [chain]: New user registered!');
userList = await contract.getUserList();
});
}
It seems like the problem was with the Infura closing the WebSocket after certain amount of idle time, and since there was no other process running except the WebSockets, the docker container was closing itself considering the job as done.
I have used the following piece of code to restart the websocket every time it closes:
provider._websocket.onclose = () => {
listenContractEvents();
};

Node.js HTTP Get stream freezes inside docker container

I have following code written in nodejs using http module.
It's basically listens to event stream (so the connection is permanent).
http.get(EVENT_STREAM_ADDRESS, res => {
res.on('data', (buf) => {
const str = Buffer.from(buf).toString();
console.log(str);
});
res.on('error', err => console.log("err: ", err));
});
If I run the above code on my Mac it works fine and I get data logged to console after many hours.
But in the Docker, which has pretty basic configuration it stops receiving data after some time without any error. Other endpoints in the app are working fine (eg. Express endpoints) but this one http.get listener is just hanging.
Dockerfile
FROM node:current-alpine
WORKDIR /app
EXPOSE 4000
CMD npm install && npm run start
Do you have any ideas how I can overcome this?
It's really hard to debug as to reproduce the situation I sometimes need to wait a few hours.
Cheers
I find out what is probably happening.
The problem is Docker Desktop for Mac. It seems it stops container sometimes like in the situation that you Mac goes to sleep. And it interrupts the listener so it stops receiving new data chunks.
I started same container on Ubuntu in VirtualBox and it works fine all the time.

How can I run some code in Node prior to running a browser test with Intern?

With Intern, how can I run some setup code in Node prior to running browser tests, but not when running Node tests? I know that I could do that outside of Intern completely, but is there anything that's a part of Intern that could handle that?
For a more concrete example: I'm running tests for an HTTP library that communicates with a Python server. When running in Node, I can run spawn("python", ["app.py"]) to start the server. However, in the browser, I would need to run that command before the browser begins running the tests.
Phrased another way: is there a built-in way with Intern to run some code in the Node process prior to launching the browser tests?
By default, Intern will run the plugins configured for node regardless of which environment you're running in.
So, you could create a plugin that hooks into the runStart and runEnd events like this:
intern.on("runStart", () => {
console.log("Starting...");
// Setup code here
});
intern.on("runEnd", () => {
console.log("Ending...");
// Teardown code here
});
These handlers will run inside the Node process, and thus have access to all the available Node APIs.
Additionally, you can detect which environments are being tested by looking at intern.config.environments:
{
environments: [
{
browserName: 'chrome',
browserVersion: undefined,
version: undefined
}
]
}
By looking at the environments, you can determine whether or not you need to run your setup code.

How to change vue-cli message after successfull compile ("App running at...")?

I use vue-cli in my dockerized project, where port mapping looks like this: "4180:8080", and the actual message after compiling my SPA looks like:
App running at:
- Local: http://localhost:8080/app/
It seems you are running Vue CLI inside a container.
Access the dev server via http://localhost:<your container's external mapped port>/app/
App works fine, I could access at via http://localhost:4180/app/ as conceived, but I'm not able to find a proper way to change the message above to show this link instead of "It seems you are running Vue CLI inside a container...". I could use webpack hooks to insert link before the message but actually wanna find the way to change the message, generated by cli. Is it possible somehow?
I came to this question - as I was looking to do the same thing with bash, running inside a Docker container (possibly what you're already doing).
You could achieve this by invoking Vue CLI commands through spawning a child node process, from within your Docker container (assuming your container is running node). You can then modify the output of stdout and stderr accordingly.
You can call a Javascript file in one of two ways:
use a shell script (bash, for example) to call node and run this script
set the entrypoint of your Dockerfile to use this script (assuming you're running node by default)
// index.js
const { spawn } = require('child_process')
const replacePort = string => {
return string.replace(`<your container's external mapped port>`, 8000)
}
const vueCLI = (appLocation, args) => {
return new Promise((resolve, reject) => {
const vue = spawn('vue', args, {cwd: appLocation})
vue.stdout.on('data', (data) => {
console.log(replacePort(data.toString('utf8', 0, data.length)))
})
vue.stderr.on('data', (error) => {
console.log(replacePort(error.toString('utf8', 0, error.length)))
})
vue.on('close', (exitCode) => {
if (exitCode === 0) {
resolve()
} else {
reject(new Error('Vue CLI exited with a non-zero exit code'))
}
})
})
}
vueCLI('path/to/app', CLI_Options).then(() => resolve()).catch(error => console.error(error))
This approach does have drawbacks, not limited to:
performance being slower - due to this being less efficient
potential danger of memory leaks, subject to implementation
risk of zombies, should the parent process die
For the reasons above and several others, this is a route that was found to be unsuitable in my specific case.
Instead of changing the message, it's better to change the port Vue is listening on.
. npm run serve -- --port 4180
This automatically updates your message to say the new port, and after you updated your docker port forward for the new port, it it will work again.

NodeJS Server getting stop on Error

I am very New to NodeJS. I am developing Live Streaming based Speech to text for my web application. It works well but problem is
Sometimes, Nodejs throws an error as 'Request Time-Out' and http server has been stop. then I need to manually re run program again (with command node app.js)
I had used this example here.
Screen shot is bello
Please help. And thanks in advance.
You need first to try {} catch(ex){}your exceptions.
You may also use pm2 which can handle that autostart if it crashes.
When using pm2 please make use of --max-memory-restart option otherwise the app can indefinitly restart and will slow down your server. That option can help you specify the amount of memory the autorestart can consume.
Install pm2
npm install -g pm2
//or
yarn global add pm2
Run the app
pm2 start app.js --max-memory-restart 100 --name node-speech
Using pm2 is even recommanded on the repository readme
you can always have a global error handler, so that, your project won't fail and also you can take an appropriate action:
process.on
(
'uncaughtException',
function (err)
{
console.log(err)
var stack = err.stack;
//you can also notify the err/stack to support via email or other APIs
}
);

Resources