-
Notifications
You must be signed in to change notification settings - Fork 123
Fix wft poll balancing with maxpoll=2 #941
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
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -102,16 +102,6 @@ impl WFTPollerShared { | |
| /// Makes either the sticky or non-sticky poller wait pre-permit-acquisition so that we can | ||
| /// balance which kind of queue we poll appropriately. | ||
| pub(crate) async fn wait_if_needed(&self, is_sticky: bool) { | ||
| // If there's a sticky backlog, prioritize it. | ||
| if !is_sticky { | ||
| let _ = self | ||
| .last_seen_sticky_backlog | ||
| .0 | ||
| .clone() | ||
| .wait_for(|v| *v == 0) | ||
| .await; | ||
| } | ||
|
|
||
| // We need to make sure there's at least one poller of both kinds available. So, we check | ||
| // that we won't end up using every available permit with one kind of poller. In practice | ||
| // this is only ever likely to be an issue with very small numbers of slots. | ||
|
|
@@ -121,26 +111,63 @@ impl WFTPollerShared { | |
| { | ||
| let mut sticky_active = sticky_active.clone(); | ||
| let mut non_sticky_active = non_sticky_active.clone(); | ||
| let mut sticky_backlog = self.last_seen_sticky_backlog.0.clone(); | ||
|
|
||
| loop { | ||
| let num_sticky_active = *sticky_active.borrow_and_update(); | ||
| let num_non_sticky_active = *non_sticky_active.borrow_and_update(); | ||
| let both_are_zero = num_sticky_active == 0 && num_non_sticky_active == 0; | ||
| if both_are_zero { | ||
| let num_sticky_backlog = *sticky_backlog.borrow_and_update(); | ||
|
|
||
| let allow = || { | ||
| if !is_sticky { | ||
| break; | ||
| // There should always be at least one non-sticky poller. | ||
| if num_non_sticky_active == 0 { | ||
| return true; | ||
| } | ||
|
|
||
| // Do not allow an additional non-sticky poller to prevent starting a first sticky poller. | ||
| if num_sticky_active == 0 && num_non_sticky_active + 1 >= max_slots { | ||
| return false; | ||
| } | ||
|
|
||
| // If there's a meaningful sticky backlog, prioritize sticky. | ||
| if num_sticky_backlog > 1 && num_sticky_backlog > num_sticky_active { | ||
| return false; | ||
| } | ||
| } else { | ||
| // There should always be at least one sticky poller. | ||
| if num_sticky_active == 0 { | ||
| return true; | ||
| } | ||
|
|
||
| // Do not allow an additional sticky poller to prevent starting a first non-sticky poller. | ||
| if num_non_sticky_active == 0 && num_sticky_active + 1 >= max_slots { | ||
| return false; | ||
| } | ||
|
|
||
| // If there's a meaningful sticky backlog, prioritize sticky. | ||
| if num_sticky_backlog > 1 && num_sticky_backlog > num_sticky_active { | ||
| return true; | ||
| } | ||
| } | ||
| } else { | ||
| let would_exceed_max_slots = | ||
| (num_sticky_active + num_non_sticky_active + 1) >= max_slots; | ||
| let must_wait = would_exceed_max_slots | ||
| && (num_sticky_active == 0 || num_non_sticky_active == 0); | ||
| if !must_wait { | ||
| break; | ||
|
|
||
| // Just balance the two poller types. | ||
| // FIXME: Do we need anything more here, to ensure proper balancing? | ||
|
Comment on lines
+154
to
+155
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Go effectively just forces there to be an even amount of both kinds of pending requests, except always favoring sticky during a backlog, and when counts are even: https://github.com/temporalio/sdk-go/blob/9682a692145f503a02b73f32435cb04bdc6f57c1/internal/internal_task_pollers.go#L782 We already are favoring it with a backlog. It's not obvious to me that just making an even amount is the best move either, but, it is what Core used to do and clearly it at least works, so we could go with that. |
||
| if num_sticky_active + num_non_sticky_active < max_slots { | ||
| return true; | ||
| } | ||
|
|
||
| false | ||
| }; | ||
|
|
||
| if allow() { | ||
| return; | ||
| } | ||
|
|
||
| tokio::select! { | ||
| _ = sticky_active.changed() => (), | ||
| _ = non_sticky_active.changed() => (), | ||
| _ = sticky_backlog.changed() => (), | ||
| } | ||
| } | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could avoid being a closure by using else-ifs... but I don't have a firm position on if that's more readable or not.