absinthe_graphql_ws icon indicating copy to clipboard operation
absinthe_graphql_ws copied to clipboard

Run each query in its own Task

Open PatrikStenmark opened this issue 1 year ago • 0 comments

Hello!

At my work we run queries over websockets, to get around Herokus limit on 30s per request. When running queries, they are run in serial, so if we have one query taking 32s, every other query will have to wait in line.

In this PR, I try to start to handle this concurrently instead. I do this by running each query in its own Task. Instead of returning the Next message in run_doc, I run run_doc in a Task, and send a message back to the "main" process.

I use a little node script to test this, which is available on https://gist.github.com/spatrik/36a69161c793e5daa1894561ea7625f9#file-1-test-ws-concurrency-mjs.

In this gist, I also have a script that runs a Phoenix server with absinthe and graphql-ws-elixir. It exposes a query foo with the arg sleep, which specifies how long the query should sleep before returning.

Running the node script with the current 0.3.6 version gives the output queries: 3.018 s. With my changes, it returns 2.012 s.

In the current state, this code is not ready for merge, but I'm curious if anyone have any thoughts if this is the right direction. I'm thinking to make it actually mergeable, I'll need to

  • Don't just start a Task. Instead I'm thinking that there should be a Task.Supervisor started when connecting. Maybe in Socket.__connect__ and then stored in the Socket struct?

  • Think about limiting the number of Tasks started. If I just start a Task for each new query, isn't that a path for DoS-ing the server? Especially if you like in my case have a query that takes 30+s. It would be pretty easy to just do 100s or 1000s of queries.

    I'm not entirely sure what is needed here. A simple solution would be to just start the Task.Supervisor with max_children set to something. I this case, if there are too many requests done on a single WebSocket at the same time, that WebSocket process would crash.

    Another option would be pulling in poolboy or something similar to make sure there are a maximum number of processes. But this is another dependency...

  • Make sure this works with subscriptions as well.

So, any thoughts on this? Am I on a good path here or am I completely lost?

PatrikStenmark avatar Apr 16 '23 19:04 PatrikStenmark