2

I'm trying to setup Websockets in order to send messages to AWS, so I can then process the message and send some payload to other resources at cloud and deliver custom responses to client part.

But, I cannot get that to work.

The main target is to send messages to AWS through WSS://, first approach with WS:// (in case that's possible), depending on payload content, it shall return a custom response. Then close the connection if no further operation is needed.

I've tried the suggestions posted here, here and here. But, either my lack of knowledge about Load Balancing, Websockets, TCP and HTTP is not letting me see pieces of solution missing, I'm doing everything wrong or both.

As for now, I have an Elastic Beanstalk example project structure like this:

+ nodejs-v1
|--+ .ebextensions
|  |--- socketupgrade.config
|
|--+ .elasticbeasntalk
|  |--- config.yaml
|
|--- .gitignore
|--- app.js
|--- cron.yaml
|--- index.html
|--- package.json

The Elastic Beanstalk environment and application are standard created, and also made sure that the Balancer is application, not classic, hence the Application Load Balancer can work with Websockets out of the box as many sources and documentation state.

It's setup with HTTP at port 80. Stickiness is enabled for a day.

Here's the code being used:

app.js:

'use strict';

const express = require('express');
const socketIO = require('socket.io');
const path = require('path');

const PORT = process.env.PORT || 3000;
const INDEX = path.join(__dirname, 'index.html');

const serber = express()
  .use((req, res) => res.sendFile(INDEX) )
  .listen(PORT, () => console.log(`Listening on ${ PORT }`));

const io = socketIO(serber);

io.on('connection', (socket) => {
  console.log('Client connected');
  socket.on('disconnect', () => console.log('Client disconnected'));
});

setInterval(() => io.emit('time', new Date().toTimeString()), 1000);

index.html:

<script src="/socket.io/socket.io.js"></script>
<script>
  var socket = io.connect('http://localhost');
  socket.on('news', function (data) {
    console.log(data);
  });
</script>

package.json:

{
  "name": "Elastic-Beanstalk-Sample-App",
  "version": "0.0.1",
  "private": true,
  "dependencies": {
    "express":"*",
    "socket.io":"*"
    },
  "scripts": {
    "start": "node app.js"
  }
}

.ebextensions/socketupgrade.config:

container_commands:
  enable_websockets:
    command: |
     sed -i '/\s*proxy_set_header\s*Connection/c \
              proxy_set_header Upgrade $http_upgrade;\
              proxy_set_header Connection "upgrade";\
      ' /tmp/deployment/config/#etc#nginx#conf.d#00_elastic_beanstalk_proxy.conf

I'm only getting 504, 502, sometimes, when tweaking configurations randomly at pointless tries, it gives me 200 and at other attempts, no protocol error, but messages like disconnection and stuff...

I appreciate your time and attention reading this desperate topic! Any hint will be appreciated as well... Just, anything... T-T

Thanks for your time and attention!

Kind regards, Jon M.

Update 1

I'll start quoting @RickBaker:

Personally, what I would do first is remove the load balancer from the equation. >If your ec2 instance has a public ip, go into your security groups and make sure >the proper port your app is listening to is open to the public. And see if you >can at least get it working without the load balancer complicating things. – >Rick Baker 21 hours ago

Changed the scaling feature of the Elastic Beanstalk environment's application from Load Balancing, Auto Scaling Environment Type to Single Instance Environment. Important to know, that I changed it from Elastic Beanstalk web page console, not from EC2 directly, since I think that it can break the Elastic Beanstalk environment application as a whole.

Anyway, changed it, after the environment and environment's application finished setting up again, changed and deployed the following:

index.html:

<script src="/socket.io/socket.io.js"></script>
<script>
    var socket = io();
</script>

After everything got running, tested with a call via webpage to the index page. And the logs from node shows life:

-------------------------------------
/var/log/nodejs/nodejs.log
-------------------------------------
Listening on 8081
Client connected
Client disconnected
Client connected

Then I started to search for Server to Server setup found this docs and then started to dig up a bit in order to connect to a WSS server.

So, the main goal is to stablish, and mantain a session from AWS EB application to another server that accepts WSS connections. The AWS EB should be responsible of stablish and mantain that connection, so when events happen at Network Server, the application at EB can send responses to the requests of events happening.

So then I read this topic, and realized that the NodeJS - socket.io approach won't work based on the posts read. So, I don't know what to do now. ( '-')

AWS EB can setup environment with Python with WSGI but, geez... Don't know what to do next. I'll try things in order to connect to WS if possible, if not then WSS, and see if something works out. So I'll Update right after I have results, whether possitive or not.

Jon over and out.

jon
  • 81
  • 1
  • 2
  • 13
  • While not a direct solution to your question. Your approach seems rather complex. Any reason you couldn't just use some type of api endpoint to achieve this, or are you using sockets because these could be long running processes? – Rick Baker Oct 17 '17 at 16:41
  • Hi @RickBaker ! The reason is that a device shall receive certain custom responses depending on the payload message sent, which is in bytes. That message gets routed and processed by a network server service, which can commmunicate to application servers via several ways. The options that seems to fit the requirement is, either `HTTP(S)` Push, or `Websockets`. So we are giving a shot to websockets. Our main goal is to have a `request`-`response` via `WS` (if possible (because of **AWS** secure measures)) at first, `WSS` (ideally) after we get `WS` to work (again, if possible). – jon Oct 17 '17 at 17:00
  • I gotcha. So the service that is running within AWS, can you actually connect to the port directly outside of trying to connect via the websocket? Meaning cal you telnet to it from where your websocket request would be coming from? – Rick Baker Oct 17 '17 at 17:02
  • Also, have you enabled proxy protocol on your elb? http://docs.aws.amazon.com/elasticloadbalancing/latest/classic/enable-proxy-protocol.html#enable-proxy-protocol-cli – Rick Baker Oct 17 '17 at 17:20
  • Nope, currently the approach I'm doing is with the use of `create_connection()` method imported from `websocket`with Python 2.7. But it returns me `504`. Can't telnet to the _Beanstalk_ URL and port given and nothing about telnet at logs (I don't know if 80 or 8081, anyway both doesn't work). Regarding the **ELB**, I'm actually using **ALB** (because of the so called "_out of the box_") feature of websocket implementation, dunno if proxy enabling at `Classic Load Balancer` applies too to the **ALB** created by **Elastic Beasntalk**. – jon Oct 17 '17 at 17:30
  • 1
    Personally, what I would do first is remove the load balancer from the equation. If your ec2 instance has a public ip, go into your security groups and make sure the proper port your app is listening to is open to the public. And see if you can at least get it working without the load balancer complicating things. – Rick Baker Oct 17 '17 at 17:42
  • I'll give it a shot. That suggestion arise a question in mind... Is the load balancing necessary? And, as a plus comment, if I deploy a simple HTTP webpage nodejs AWS sample project package, without websockets, it works indeed out of the box. But again, is `HTTP` webpage, not websockets above `HTTP`. – jon Oct 17 '17 at 18:21
  • The load balancer while not required for a single server app does give some useful advantages. Things like surge queue, where if your application can't handle the request at that given moment instead of just being dropped it would go into the elb surge queue. – Rick Baker Oct 17 '17 at 18:28
  • Hi @RickBaker! You're awesome!!! I can see signs of life turning down the _Load Balancer_. But, I'm starting to struggle... Because I just noticed [here](https://github.com/socketio/socket.io/issues/2981) that is not possible to make **AWS** `websocket` connect a session with a "pure" `WSS` server in order to later take in requests. So, *AWS* connects to Network Server, then waits for requests from network server, exchange message depending on payload and then close the connection. Geez, I'll update later the topic. I'll update the achievements or milestones reached. Thanks! – jon Oct 17 '17 at 23:15

1 Answers1

0

After combining previous iterations with some more documentation reading, I came to realize that, the connection indeed starts from AWS, via NodeJS using ws.

So I'm able to communicate with Network Server via WSS and request and provide data.

The app.js:

var WebSocket = require('ws');
var wss = new WebSocket('wss://example.com');

wss.on('open', function connection() {
    console.log("WSS connection opening")
});

wss.on('message', function incoming(data) {
    console.log("Jot:")
    console.log(data)
    setTimeout(function timeout() {
        console.log("Sending response")
        wss.send(JSON.stringify(
            {
                "key": "Hi there"
            }
            ));
        }, 
    500);
});

The package.json:

{
  "name": "Elastic-Beanstalk-Sample-App",
  "version": "0.0.1",
  "private": true,
  "dependencies": {
    "express":"*",
    "socket.io":"*",
    "ws": "*"
    },
  "scripts": {
    "start": "node app.js"
  }
}

The structure of the project remains almost the same:

+ nodejs-v1
|--+ .ebextensions
|  |--- socketupgrade.config
|
|--+ .elasticbeasntalk
|  |--- config.yaml
|
|--- .gitignore
|--- app.js
|--- cron.yaml
|--- package.json

As you can see, there's no index.html since it's not used.

From here, now it's up to the solution requirements the usage of sending/receiving data. And to make sure the connection is established/recovered.

karel
  • 5,489
  • 46
  • 45
  • 50
jon
  • 81
  • 1
  • 2
  • 13