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

Add async option to Absinthe.Subscription #1329

Merged
merged 4 commits into from
Aug 15, 2024

Conversation

bryanjos
Copy link
Contributor

@bryanjos bryanjos commented Jul 23, 2024

We have an app that is a heavy user of subscriptions. We noticed that one of our servers were failing health checks, causing it to restart. Eventually we found that we were running into an issue of unbounded concurrency that led us to the proxy here in absinthe. We resolved it by simply removing the task supervisor. This creates a bottleneck here that limits concurrency. It doesn't completely limit concurrency though as the user can still control the level of concurrency via the pool option.

This PR adds the option to allow Proxy to handle events from pubsub async or not.

@bryanjos bryanjos requested a review from a team July 23, 2024 16:23
@bryanjos bryanjos marked this pull request as ready for review July 23, 2024 16:23
@benwilson512
Copy link
Contributor

hey @bryanjos notably the trade off here is that these processes are also now more likely to have their message queue grow if the pool can't keep up.

I get the change here, but I think we also need to probably look at some overflow protection ideas here too.

@benwilson512
Copy link
Contributor

The other thing to note here is that the theory was that if your user base is evenly distributed between the nodes, the activity coming in via these processes would be no worse than the activity driven by user engagement, so as long as that wasn't OOMing you should be good. If that isn't holding then can you elaborate a bit on what is driving the subscription publication?

@bryanjos
Copy link
Contributor Author

@benwilson512 I recognize the tradeoff and even brought it up when this was suggested by a teammate. But somehow it's behaving fine now.

It is supposed to be temporary though. Ideally we'd want something with some back pressure there and controlled concurrency. For instance, I proposed a change in our fork to add gen_stage and created a producer that listened for pubsub changes that were picked up by a ConsumerSupervisor where the max concurrency was equal to max_demand.

So maybe this solution wouldn't work here, and maybe one with some added back pressure would? Or at least the ability to customize that part of things. Some of that is already possible. Changing whatever module implements Absinthe.Subscription.Pubsub.publish_mutation to instead broadcast the message to a different topic that the proxy is listening to, to some other processes with back pressure can get you there.

What is driving our subscription publication is changes to uploaded files from our media pipeline. The users listening for subscriptions are evenly distributed across nodes. We never ran out of memory but there was so many processes that our health check was taking too long to get a response from absinthe saying it was alive. Maybe #1330 solves that though as it was causing a lot of waiting.

@bryanjos
Copy link
Contributor Author

@benwilson512 any more thoughts on this?

I'm thinking if this isn't acceptable, is there any existing mechanism for customizing that part of proxy? Or anything we could introduce?

Ultimately I'm thinking some form of back pressure might be needed. And if that's the direction we should go, I can close this and propose something around that.

@benwilson512
Copy link
Contributor

@bryanjos can you make this an option perhaps? This way the default behavior can be async but if you want you can do {Absinthe.Subscription, async: false} and then it does this sync based logic?

@bryanjos
Copy link
Contributor Author

@benwilson512 yes I can do that! Will update it soon

@bryanjos bryanjos changed the title Fix unbounded concurrency Optionally allow Proxy to handle events asynchronously Aug 15, 2024
@bryanjos bryanjos changed the title Optionally allow Proxy to handle events asynchronously Optionally allow Proxy to handle events synchronously Aug 15, 2024
@bryanjos bryanjos changed the title Optionally allow Proxy to handle events synchronously Add async option to Absinthe.Subscription Aug 15, 2024
@bryanjos
Copy link
Contributor Author

@benwilson512 I made the changes. Let me know what you think. I also updated the changelog with the unreleased PRs merged

Copy link
Contributor

@benwilson512 benwilson512 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great, thanks!

@benwilson512 benwilson512 merged commit 0ebe9cb into main Aug 15, 2024
15 checks passed
@benwilson512 benwilson512 deleted the bryanjos/unbounded_concurrency_fix branch August 15, 2024 16:02
@bryanjos
Copy link
Contributor Author

Awesome! Thanks!

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.

2 participants