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

Promise v3 #1157

Merged
merged 22 commits into from
Nov 20, 2024
Merged

Promise v3 #1157

merged 22 commits into from
Nov 20, 2024

Conversation

key2peace
Copy link
Collaborator

No description provided.

- changed ExtendedPromiseInterface to PromiseInterface
- replaced Discord\Helpers\Deferred with React\Promise\Deferred
- changed ->done(true function, false function) with ->then(true function)->catch(false function)
- changed ->always() to ->finally()
- added use React\Promise\Deferred where I think it was missing
- updated $deferred->resolve() to $deferred->resolve(true)
- updated $deferred->reject() to $deferred->reject(throwable)
@key2peace key2peace marked this pull request as draft July 17, 2023 14:45
@SQKo SQKo added the dependencies Pull requests that update a dependency file label Jul 22, 2023
@2colours
Copy link

@key2peace what is the state of this PR? Being stuck with v2 Promises (thanks, Composer, for not handling multiple versions of one package btw) means even something as banal as set_rejection_handler cannot be used.

@SQKo
Copy link
Member

SQKo commented Mar 16, 2024

@key2peace what is the state of this PR? Being stuck with v2 Promises (thanks, Composer, for not handling multiple versions of one package btw) means even something as banal as set_rejection_handler cannot be used.

It wont be in v10, many dependencies still stuck with v2 promises
As well compatibility issue with future php 8.4 version, which they'll promise to support by reactphp v3

about set_rejection_handle, Just be careful with your promise codes for now
always use then() followed by argumentless and empty done() so you can refactor your code easier in future

@2colours
Copy link

2colours commented Mar 16, 2024

@SQKo DiscordPHP should at the very least handle the rejection path with a logger, with a log level >= warning. There is no reason to not do that since afterwards nobody could even catch the rejection currently. I think that's way better than leaving it up to the consumers to develop some quasi framework that minimizes the boilerplate for handling this for each and every registered command.

I'm already looking into the code; it's just not easy to navigate around with something you have only been actively using for like 2 months...

@2colours
Copy link

see #1208

This is anything but exhaustive, it just covers my most obvious use case.

@SQKo
Copy link
Member

SQKo commented Mar 16, 2024

@SQKo DiscordPHP should at the very least handle the rejection path with a logger, with a log level >= warning. There is no reason to not do that since afterwards nobody could even catch the rejection currently. I think that's way better than leaving it up to the consumers to develop some quasi framework that minimizes the boilerplate for handling this for each and every registered command.

I'm already looking into the code; it's just not easy to navigate around with something you have only been actively using for like 2 months...

We know about it already, unfortunately the issue we are facing might be also caused by dependencies, our code is fine when web socket is not connected yet..

Regarding to your suggestion, we already considered about it, but it is wrong to log everything even those promise rejections already handled/caught by users and not respecting users configured Logger.
So we went to a better idea, It is somewhat already implemented but if i recall, it requires your code to be wrapped inside a coroutine yields so your own code throws will be also forwarded:

if ($e instanceof \Error) {
throw $e;
} elseif ($e instanceof \Exception) {
$this->logger->error('exception while trying to handle dispatch packet', ['packet' => $data->t, 'exception' => $e]);
} else {
$this->logger->warning('rejection while trying to handle dispatch packet', ['packet' => $data->t, 'rejection' => $e]);
}

notice why it is logged only in websocket events because it only gets silence after websocket connected...

Due to the nature of promise chain, where this library being in middle position, the ideal solution has to be implemented on user's end.
It's not true that nobody can even catch the rejection, thats why I previously remind the proper use of then() and done(). Same for this library perspective, if the dependency does not handle promise rejection properly, it can never be caught by us.

@discord-php discord-php locked as off-topic and limited conversation to collaborators Mar 30, 2024
@valzargaming valzargaming marked this pull request as ready for review November 20, 2024 14:07
@valzargaming
Copy link
Member

wyrihaximus/react-cache-redis is currently locked to ^3.0 || >=4.0 <4.4 and we are required to use at least ^4.5.0 to include react/promise ^3.1. This is considered to be a core feature of the v10 library to support external caching and must be tested before this can be included as part of a new release.

@valzargaming valzargaming requested review from Log1x, Exanlv, a team and valzargaming November 20, 2024 14:12
@valzargaming
Copy link
Member

valzargaming commented Nov 20, 2024

Tested with Civilizationbot and wyrihaximus/react-cache-redis ^4.5 and all is well. This introduces BC for React\Promise\resolve and React\Promise\reject and values must be passed for both: value for resolve (even null is fine) and a \Throwable for reject. Similarly v3 has deprecated functions like React\Promise\map and userland implementations will need to use React\Promise\all or React\Promise\any instead.

$promise = coroutine([$event, 'handle'], $guild);

$promise->done(function ($d) use (&$unavailable) {
$promise->then(function ($d) use (&$unavailable) {
Copy link
Member

Choose a reason for hiding this comment

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

All Instances of $promise->then need to take parameters (callable $onFulfilled, callable $onRejected); Let's get these functions either defined as $variable = function()s or make some generic handlers we can throw in that will make relevant calls to Monolog

Copy link
Member

Choose a reason for hiding this comment

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

Per the release notes; It is no longer possible to resolve a promise without a value (use null instead) or reject a promise without a reason (use Throwable instead).

@@ -499,7 +498,7 @@ protected function handleReady(object $data)
unset($unavailable[$guild->id]);
}
if (count($unavailable) < 1) {
$guildLoad->resolve();
$guildLoad->resolve(true);
Copy link
Member

Choose a reason for hiding this comment

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

Instead of resolve(true) let's change these to resolve(null) as recommended per the release notes: https://github.com/reactphp/promise/releases/tag/v3.0.0

@valzargaming valzargaming merged commit a9bb7fc into master Nov 20, 2024
1 check passed
@valzargaming valzargaming linked an issue Nov 20, 2024 that may be closed by this pull request
7 tasks
@valzargaming valzargaming added this to the 10.0 milestone Nov 20, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
dependencies Pull requests that update a dependency file
Projects
No open projects
Development

Successfully merging this pull request may close these issues.

Promises v3 Checklist
4 participants