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

Initial release #2

Merged
merged 15 commits into from
Nov 17, 2024
Merged

Initial release #2

merged 15 commits into from
Nov 17, 2024

Conversation

maxime-rainville
Copy link
Member

@maxime-rainville maxime-rainville commented Nov 10, 2024

Copy link

@marwan38 marwan38 left a comment

Choose a reason for hiding this comment

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

Generally looks good, though a few things I'd personally resolve.

An important bit I want to discuss is:

  1. Dealing with futures explicitly, as in, returning them where relevant in case we ever want to do something with them.
  2. Clearly distinguishing between amphp and revolt. We're mixing APIs - we should be intentional with what's used and where. At the moment, you don't need amphp at all.. you can drop it completely. If we keep it (and tie ourselves into it) then we should utilise their APIs. General feeling of this repo is that it doesn't need amphp. EDIT: If we want Futures to be our API then yes, we should stick completely to the amphp apis
  3. We need to consider signals and event cancellation and referencing. All EventLoop::* apis return a callbackId that you can use to do many things, a few of them: unreference the callback, cancel the callback, etc.. These should probably be part of the higher API of this library.
  4. The API should expose an API for cancellations for library consumers: https://amphp.org/amp#cancellation

Choose a reason for hiding this comment

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

Beautiful

$listenerProvider->addListener(UserCreatedEvent::class, function (UserCreatedEvent $event) {
// Simulate async operation
EventLoop::delay(1, fn () => null);
echo "Sending welcome email to {$event->email}\n";

Choose a reason for hiding this comment

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

This echo is meant to be within the delay callback I believe. or do you mean to use the delay() function to [async] block?

public function __construct(
ListenerProviderInterface $listenerProvider
) {
$this->listenerProvider = $listenerProvider;

Choose a reason for hiding this comment

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

Nitpick: construction promotion or whatever it's called.

public function __construct(private Type $var){}

src/AsyncEventDispatcher.php Outdated Show resolved Hide resolved
EventLoop::queue(function () use ($event, $listener) {
$listener($event);
});
}

Choose a reason for hiding this comment

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

I'm still not clear on when to use amp and when to use the lower level api of Revolt.

awaitAll(
    array_map(
        fn ($listener) => async(fn() => $listener($event)),
        $listeners
    )
)

for example would be the amphp api. We're also using the 2 APIs without clarification (compare this to dispatchStoppableEvent for example.

}
});

return $event;

Choose a reason for hiding this comment

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

I wonder if we should be returning the futures?
// @return Future<StoppableEventInterface>[] for example.

Copy link
Member Author

Choose a reason for hiding this comment

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

That's a good idea.

For context, the stated return type for the dispatch method according to PSR-14 is @return object The Event that was passed, now modified by listeners.

So strictly speaking we should be returning the same event we got as an input. In practice, this will be useless because our listeners will be executed later, so they will not have had a chance to do anything to our event yet. I think returning a Future make sense here.

Choose a reason for hiding this comment

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

We can stick to the standard and expose a getFuture() method on the events. You did say that an Event could be anything under this standard, so it makes perfect sense to add this to the event itself.

src/AsyncEventDispatcher.php Show resolved Hide resolved
src/AsyncEventDispatcher.php Outdated Show resolved Hide resolved
src/ListenerProvider.php Outdated Show resolved Hide resolved
$completed = false;

$this->listenerProvider->addListener(TestEvent::class, function (TestEvent $event) use (&$results) {
EventLoop::delay(0.1, fn () => null);

Choose a reason for hiding this comment

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

delay(0.1);
echo 'after waiting 0.1 seconds';

Copy link
Member Author

Choose a reason for hiding this comment

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

I don't really want my test to be echoing things to the console though.

Choose a reason for hiding this comment

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

It was just pseudocode, perhaps I misunderstood your test. I was just pointing out that the EventLoop::delay() here does almost nothing.. I thought you were specifically trying to block execution with a sleep (delay in the context of amphp).

composer.json Outdated
"@test"
]
},
"license": "MIT",
Copy link
Member Author

Choose a reason for hiding this comment

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

I used BSD-3 for my other project. MIT is essentially the same thing.

Claude decided to use MIT. Probably should add a LICENSE.MD file.

src/AsyncEventDispatcher.php Outdated Show resolved Hide resolved
src/AsyncEventDispatcher.php Show resolved Hide resolved
}
});

return $event;
Copy link
Member Author

Choose a reason for hiding this comment

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

That's a good idea.

For context, the stated return type for the dispatch method according to PSR-14 is @return object The Event that was passed, now modified by listeners.

So strictly speaking we should be returning the same event we got as an input. In practice, this will be useless because our listeners will be executed later, so they will not have had a chance to do anything to our event yet. I think returning a Future make sense here.

src/ListenerProvider.php Outdated Show resolved Hide resolved
$completed = false;

$this->listenerProvider->addListener(TestEvent::class, function (TestEvent $event) use (&$results) {
EventLoop::delay(0.1, fn () => null);
Copy link
Member Author

Choose a reason for hiding this comment

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

I don't really want my test to be echoing things to the console though.

@maxime-rainville
Copy link
Member Author

maxime-rainville commented Nov 13, 2024

@marwan38
I think I answered most of you feedback.

I made the dispatch method return a Future. I also added the ability to send a cancellation to the dispatch.

@marwan38
Copy link

marwan38 commented Nov 13, 2024

@marwan38 I think I answered most of you feedback.

I made the dispatch method return a Future. I also added the ability to send a cancellation to the dispatch.

Nice, I did leave an updated comment on that regarding futures. I'll touch on it again to emphasize: We can expose a getFuture() on the events to get the futures and sticking to the PSR14 spec. It might make for a better API too.

LGTM and ready to approve, but, you need to consider ☝️ first.

@maxime-rainville
Copy link
Member Author

We can stick to the standard and expose a getFuture() method on the events. You did say that an Event could be anything under this standard, so it makes perfect sense to add this to the event itself.

We could create our own AsyncAwareEvent class/interface and get the dispatcher to handle that one differently ... the same way that it's handling StoppableEvents differently.

I did update the dispatch method to have the dispatch(T event): Future<T> signature. I think that effectively accomplishes the same thing as having an specialized Event class with a getFuture() method.

@maxime-rainville maxime-rainville merged commit e33f638 into 0 Nov 17, 2024
8 checks passed
@maxime-rainville maxime-rainville deleted the master branch November 17, 2024 20:42
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