openfaas / of-watchdog

Reverse proxy for STDIO and HTTP microservices
MIT License
263 stars 115 forks source link

Websockets and HTTP mode #20

Closed rosko closed 4 years ago

rosko commented 6 years ago

Is it possible to use of-watchdog in HTTP mode to support websockets?

Your Environment

alexellis commented 6 years ago

Not right now since we'd have no way of giving QoS i.e. timeouts etc.

What is the usecase for a websocket to a function? How would you see timeouts working with this?

Alex

rosko commented 6 years ago

We can consider a websocket server as a set of event handlers: connection, disconnect, message. In this case, it seems possible to be implemented using functions. And timeouts can work with that concept similarly as with regular serverless functions. Does it make sense?

alexellis commented 6 years ago

Websockets are inherently stateful with long running connections. How do you implement a timeout for an operation?

Maybe you could start with giving us a usecase in as much detail as you're comfortable with and we can try to explore the idea from there?

rosko commented 6 years ago

I think it's better for me to explain using node8-express-template as an example. (https://github.com/openfaas-incubator/node8-express-template)

This template contains:

In the case of WebSocket, there will be a similar structure: one main script that initializes websocket server and one or many handlers.

index.js

const WebSocket = require('ws');
const connectionHandler = require('./function/connection.js');
const messageHandler = require('./function/message.js');
const disconnectHandler = require('./function/disconnect.js');

const wss = new WebSocket.Server({ port: 8080 });

wss.on('connection', function connection(ws, req) {
  connectionHandler(wss, ws, req);
  ws.on('message', function (message) {
    messageHandler(wss, ws, req, message);
  });
  ws.on('disconnect', function() {
    disconnectHandler(wss, ws, req);
  });
});

function/message.js

module.exports = (wss, ws, req, message) => {
  // Broadcast to everyone else.
  wss.clients.forEach(function each(client) {
    if (client !== ws && client.readyState === WebSocket.OPEN) {
      client.send(data);
    }
  });
}

So, we can measure timeouts for every websocket event – how much time it takes to handle the event using handler. Makes sense? Or I'm too naive and missing something? :)

rosko commented 6 years ago

@alexellis WDUT?

rvanzon commented 5 years ago

@rosko hi, I have the same question actually. Did you ever tried this out?

rosko commented 5 years ago

@rvanzon not yet :)

lucasvfventura commented 5 years ago

@alexellis My team is using GraphQL and we use subscriptions to push events to the UI that were triggered by other users. Subscriptions use Websocket behind the scene. This is the only point keeping us to move to a completely serverless solution.

Serverless.com with AWS supports it with the "new" API Gateway websockets api, but it isn't available yet in my GraphQL framework integration with the serverless framework.

matti commented 4 years ago

my usecase: run https://github.com/ws-doom

alexellis commented 4 years ago

I'm going to close this issue as it's already been answered.

We may consider websocket support in the future, however we've had no requests from commercial users for this as of yet. Ideally, we'd be looking for one of them to sponsor the work and maintenance of the feature. It would also break any timeouts and limits that people expect from FaaS platforms like OpenFaaS and Cloud Run.

colearendt commented 1 year ago

Just want to add some context here. In addition to streaming applications, there are a handful of app development frameworks in the data science ecosystem (Shiny, Streamlit, etc.) that depend heavily on websockets. The other place I have seen applications are in TTYs (terminal-emulators) and other heavily responsive / stateful applications.

With regard to how to set timeouts, I have seen many transparent proxies use something like "proxy read timeout" or "proxy write timeout.". In traefik (written in Go), idleTimeout seems to be the operative target.

In any case, websockets or other keep-alive connections seem to be handled independently of other types of requests.

The behavior that I experienced with fwatchdog not handling websockets definitely surprised me and took a while to debug - it just holds the socket open and doesn't return the data until the backend connection dies or fwatchdog's shutdown sequence is initiated. tcpdump on the container (which showed my function returning data from 8082->8080, and data never getting returned from 8080) was what finally led me to this thread.

(FWIW I'm not sure if this is the right GitHub repo or if I am using the "classic" watchdog, but this seemed like the newer target for feature discussions!). If I find someone willing to finance or if I find time to mock up a PR, I will let you know 😄