Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Run each query in its own Task #21

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

PatrikStenmark
Copy link

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 PatrikStenmark changed the title Run each queries in its own Task Run each query in its own Task Apr 16, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant