-
Notifications
You must be signed in to change notification settings - Fork 20
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
Improve Condition #184
base: main
Are you sure you want to change the base?
Improve Condition #184
Conversation
@Atry has imported this pull request. If you are a Meta employee, you can view this diff on Phabricator. |
I am not sure about the memory leak part. Given the following code async function outer(): Awaitable<void> {
await wait_for_notification_async(
async $notifyee ==> {
concurrent {
await async {
await gen_usleep(100);
$notifyee->trySucceed("fast condition");
}
await async {
await gen_usleep(10000000000);
$notifyee->trySucceed("slow condition");
}
}
}
);
} I want the unfinished "slow condition" not to prevent the |
@Atry has imported this pull request. If you are a Meta employee, you can view this diff on Phabricator. |
@Atry has imported this pull request. If you are a Meta employee, you can view this diff on Phabricator. |
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.
Requesting changes for small nits and potential for enum classes. Naming TBC.
Will need www performance checks (will comment on internal diffs)
Overall like the removal of the fixme and more explicit states.
|
||
namespace HH\Lib\_Private; | ||
|
||
use type HH\Lib\Async\Condition; |
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.
don't use use type
or use function
in the HSL outside of tests; we want use namespace HH\Lib\Async;
AsyncResult::class, | ||
Finished::class, | ||
)>> | ||
interface ConditionState<T> { |
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 API feels a lot like a
Promise
; would that be a better naming? - this + the interfaces potentially feels like a good use case for
enum class
- would that make sensehere?
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.
AsyncResult
and SyncResult
cannot be enum class
es because they contain properties. Finished
and NotStarted
can be turned into enum class
es.
src/async/Condition.php
Outdated
/* HH_FIXME[4110]: Type error revealed by type-safe instanceof feature. See https://fburl.com/instanceof */ | ||
$this->condition->succeed($result); | ||
if (!$this->state->trySucceed($this, $result)) { | ||
invariant_violation('Unable to notify Condition twice'); |
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.
use invariant($condition, $message)
instead
src/async/Condition.php
Outdated
); | ||
$this->condition->fail($exception); | ||
if (!$this->state->tryFail($this, $exception)) { | ||
invariant_violation('Unable to notify Condition twice'); |
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.
ditto
return $condition->waitForNotificationAsync($notifiers($condition)); | ||
} | ||
|
||
interface ConditionNotifyee<-T> { |
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.
Similarly feels like a Promise
API
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.
I used to name it Promise
but the API is different from Promise
in either Scala or JavaScript. The current version named it ConditionNotifyee
because it is used with the wait_for_notification_async API.
The primary purpose of this interface is to hide the setState
function from public API.
): Awaitable<T> { | ||
$condition = new Condition(); | ||
return $condition->waitForNotificationAsync($notifiers($condition)); | ||
} |
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.
- at a minimum, this needs a similar 'do not use' comment to
Async\Poll
- AIUI this is a control flow that we specificially do not want to make easier/more straightforward, due to ease of misuse (e.g. it can make it easy to make your request 10% faster by reducing server concurrent requests by 20%, in a way that doesn't show up in request-isolated benchmarking)
It will not block Also an invariant violation will always trigger in this example. The 'good' uses of awaiting in a loop, and async generators are when everything will eventually be processed, but need to be processed in order. Most uses are inappropriate and should be The 'good' uses of AsyncPoll are when everything passed in will eventually be awaited, but execution is independent - similar to a scheduler without cancellation. In general, 'start but do not finish' or 'ignore everything except the first result' is bad for site health, and not something we want to support in hack - but unfortunately the primitives we need to support the 'good' cases also enable the 'bad' cases. |
I think it would not trigger an invariant violation because it uses |
Still not sure it's desirable, but if a higher level function is needed, you don't need the notifier to be part of the public API: function can either return or throw, either will be considered resolving the awaitable. There isn't a need for explicit succeed/fail calls, and probably isn't even a need for explicit catching - the exception will be stored in the awaitable by default. This would also remove the possibility of weirdness if e.g. people don't return immediately after indicating success or failure |
1. Introduce the ADT type ConditionState to replace ?Awaitable<T>, suppressing HH_FIXME[4110] 2. Added a Finish state to remove the reference from the child awaitable to the Condition, in case of memory leak 3. Added wait_for_notification_async and ConditionNotifyee to hide the setState function
This PR had multiple purposes. I just split the |
@Atry has imported this pull request. If you are a Meta employee, you can view this diff on Phabricator. |
Hi @Atry! Thank you for your pull request. We require contributors to sign our Contributor License Agreement, and yours needs attention. You currently have a record in our system, but the CLA is no longer valid, and will need to be resubmitted. ProcessIn order for us to review and merge your suggested changes, please sign at https://code.facebook.com/cla. If you are contributing on behalf of someone else (eg your employer), the individual CLA may not be sufficient and your employer may need to sign the corporate CLA. Once the CLA is signed, our tooling will perform checks and validations. Afterwards, the pull request will be tagged with If you have received this in error or have any questions, please contact us at [email protected]. Thanks! |
ConditionState
to replace?Awaitable<T>
in the original implementation, removingHH_FIXME[4110]
Finish
state to remove the reference from the child awaitable to theCondition
, in case of memory leakwait_for_notification_async
andConditionNotifyee
to hide thesetState
functionTest Plan: