Scaling my web app to 2 web proceses on Heroku breaks Nowjs/Sockets.io.
I'm using full stack that is new to me and everything works great until I add a 2nd web process. Node.js still responds fine but Nowjs stops responding. I get 503 responds in the browser and
GET musicbacon.com/socket.io/1/?t=1339117661910 dyno=web.2 queue=0 wait=0ms service=2ms status=200 bytes=82
2012-06-08T01:07:42+00:00 heroku[router]: Error H13 (Connection closed without response) -> GET musicbacon.com/socket.io/1/websocket/12401614301555103827 dyno=web.2 queue= wait= service= status=503 bytes=
on the server.
I think that Nowjs (which is an abstraction layer on top of Socket.io) creates it's own server along side my Node.js server. Scaling Heroku spins up a new Node.js server VM but since Now.js isn't yet compatible with distributed environments it just dies.
Hopefully I'm missing something and I can scale Now.js because 1 Heroku web process can only handle about 60 users at a time in my experience.
Full stake is:
Heroku
Node.js
Express
Jade
Now.js
Postgres
Error H13 reference: https://devcenter.heroku.com/articles/error-codes#h13__connection_closed_without_response
WebSockets don't work on Heroku, you need to change your Socket.IO configuration to disable WS:
https://devcenter.heroku.com/articles/using-socket-io-with-node-js-on-heroku
https://devcenter.heroku.com/articles/request-timeout#longpolling_and_streaming_responses
https://github.com/LearnBoost/Socket.IO/wiki/Configuring-Socket.IO
Related
I am trying to deploy server side of MERN app on heroku but got stuck on code=H12 desc="Request timeout", even though the message "DB was successfully connected" from mongoose.connect() method, is shown, so I have whitelisted IPs on mongoDB Atlas, but still can't find the issue.
Thank you,
Total noob here, and currently learning node.js and all the fun it can procure.
I am wrote a REST API with node/express, with a database in mongoDB (and mongoose in my code).
The database is a free one hosted on AWS (through the mongoDB website).
I am calling the following endpoint :https://rewaer-backend.herokuapp.com/api/users/ with postman.
Here is how the route look like:
// GET all users
router.get("/", async (req, res) => {
try {
const user = await User.find();
res.json(user);
}
catch (err) {
res.status(400).json({ message: err });
}
});
but I a getting the following error from heroku:
2020-10-07T14:39:58.684608+00:00 heroku[router]: at=error code=H12
desc="Request timeout" method=POST path="/api/users/"
host=rewaer-backend.herokuapp.com
request_id=94d50342-514e-45e7-94ad-5cb1acde44fa fwd="37.120.11.242"
dyno=web.1 connect=1ms service=30001ms status=503 bytes=0
protocol=https
My collection "users" has only two set of data. Also, really small. When running the server in local (connected to the DB on AWS) this works fine. As you can see in my code, I should be returning something, even if an err happens. So no reason to timeout here.
The Heroku logs show that the connection to the db is successful.
I have no idea what is not working here, and google was not able to help me any further: hence me asking the real wise people ;)
Thanks a lot for any help,
Clément
The default server selection timeout in MongoDB drivers is 30 seconds. Heroku also has a 30 second timeout in its routing layer for the app server to produce the response.
Change server selection timeout to a lower value.
Then fix MongoDB connectivity issues you have (likely IP whitelist).
I wrote a simple GraphQL server using Apollo Express and deployed it to Heroku. After some messing around with Procfiles and the like, it built OK.
When I hit the main URL https://limitless-atoll-59109.herokuapp.com I get the error
Cannot GET /
OK, then I thought the Express server must just be looking for a get on the graphql endpoint. But when I hit https://limitless-atoll-59109.herokuapp.com/graphql I get
GET query missing.
Do I need to include a port in the url? I've got the port set correctly in the code
const PORT = process.env.PORT || 4000
app.listen({port: PORT}, () =>
console.log(`Server ready at http://localhost:${PORT}${server.graphqlPath}`)
);
but I don't think I need to include it when accessing the server on Heroku, do I?
For what it's worth, this is the error in the error logs
019-05-08T17:07:41.492327+00:00 heroku[router]: at=info method=GET
path="/graphql" host=limitless-atoll-59109.herokuapp.com
request_id=b6171835-aac4-4b45-8a7b-daebbb3167ed fwd="139.47.21.74"
dyno=web.1 connect=0ms service=900ms status=400 bytes=196
protocol=https
Thanks for any help!
The answer is that it is the url that ends in /graphql that one wants. However, when you hit that url from the browser, it attempts to load the playground, and fails, as the playground is disabled by default in production.
However, you can make graphql calls against that url from your client app and it works fine.
If you are using apollo server you can just enable it in production:
const server = new ApolloServer({
typeDefs,
resolvers,
introspection: true,
playground: true,
});
My node app is receiving some mysterious CONNECT requests and I'm trying to get to the bottom of where these are coming from (see separate post here).
I'm using the express module and until now, incoming CONNECT requests would just be fended off automatically with a 503 response.
But now, in order to examine the headers of these CONNECT requests, I'm trying to implement handling of such requests using the express module, if only just to dump the headers to the console and then send a 503 response myself.
Given the express seems to provide handling of connect as well as get and post (see here), this is what I've tried so far:
var connectHandler = function(req, res) {
console.log(JSON.stringify(req.headers));
res.sendStatus(503);
};
var app = express();
app.connect('*', connectHandler);
But the behaviour of the node app doesn't change... i.e. nothing is dumped to console when an incoming CONNECT request is received, with the CONNECT request being fended off and with the following entry in the log (just as before):
Oct 27 14:14:25 example heroku/router: at=error code=H13 desc="Connection closed without response" method=CONNECT path="example.herokuapp.com:443" host=example.herokuapp.com request_id=353e623x-dec4-42x5-bcfb-452add02ecef fwd="111.22.333.4" dyno=web.1 connect=0ms service=1ms status=503 bytes=0
Any help appreciated.
Deploying my app on Heroku breaks websockets protocol.
It works on localhost, not on Heroku. In browser, I get :
WebSocket connection to 'wss://node-omi.herokuapp.com/socket.io/?EIO=2&transport=websocket&sid=*' failed: Error during WebSocket handshake: Unexpected response code: 503
On the server side, I get in logs:
2014-08-12T15:05:24.761611+00:00 heroku[router]: at=error code=H13 desc="Connection closed without response" method=GET path="/socket.io/?EIO=2&transport=websocket&sid=****" host=node-omi.herokuapp.com request_id=* fwd="*" dyno=web.1 connect=3ms service=3ms status=503 bytes=864
This is a part of my server script:
var express = require('express'),
http = require('http'),
socket_io = require('socket.io');
var app = express(),
server = http.Server(app),
io = new socket_io(server).of('/test');
io.on('connection', this.connection.bind(this));
app.get('/client.html', function(req, res, next) { ... });
app.use('/', express.static(__dirname + '/public', {'index': ['index.html']}));
server.listen(process.env.PORT || 5000);
What's wrong with my code ? Does anyone succeed in building a socket.io server with Express 4.8.3 and Socket.io 1.0.6 ? The socket works with polling, but I really need websockets to work. Thanks for replies.
Websocket support on Heroku has since gone from beta to official support, so at the time of this post the fix might have been to simply labs:enable websockets But you should no longer need to do this, you get websockets out of the box.
Warning!
But as a warning to others reading this question, using socket.io on Heroku can be problematic because of a disagreement around sticky sessions
Heroku explicitly stands against them but (short of a rather crappy workaround described below) socket.io requires them:
https://github.com/Automattic/engine.io/issues/261
^The tl;dr if this very long thread is that before v1.0, socket.io worked with non-sticky services like Heroku, you just needed to use a redis adapter to manage shared state across your dynos. This was removed in 1.0 and the socket.io team is apprehensive to put it back due to the code maintenance cost. The github issue asking to have it back has been closed with the message that they'll be happy to look into it as soon as someone wants it badly enough to make a PR.
Workaround!
There is a workaround which is to restrict socket.io to using websocket transport only, which does not require sticky sessions. Eg:
Server:
io.set('transports', ['websocket']);
Client
var socket = io.connect(host, {
transports: ['websocket']
});
However, this removes much of the benefit that socket.io 1.0 brings with its use of engine.io.
There are other websocket frameworks like Faye that work very nicely on Heroku.