embarklabs / embark

Framework for serverless Decentralized Applications using Ethereum, IPFS and other platforms

Home Page:https://framework.embarklabs.io/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Proposal: Runtime exceptions for requesting non-registered events

0x-r4bbit opened this issue · comments

Proposal description

Embark allows for registering different kind of events and their event handlers throughout various stack components and plugins.

To enable run-time extensibility, it is allowed to request events that might not exist. The idea is that, if a certain module/plugin doesn't exists, isn't setup/configured, Embark should just still work without falling apart.

In practice this is only partially a great thing because there's not error handling for such cases, leaving Embark in limbo and making it hang forever.

I'd like to propose that we introduce explicit run-time error handling for cases where any component inside Embark, whether bootstrapped at Embark's bootstrap phase, or later at run-time by installing and running a plugin, tries to request any event that hasn't been registered.

This will improve the developer experience as it will make very clear why Embark isn't able to move on, and prevents developers from staring at an invalid state without any useful information.

This will go hand-in-hand with: #911

I'm torn on this one. On one hand, I totally agree that having hangs because of events not being registered is a pain in the ass and having errors/warnings really helps.

On the other hand, I also know that some commands are getting called in a fire and forget manner. Example: the command to add console commands is really not a big deal if it fails, because it doesn't wait on anything and in the case of embark test, it needs the ENS modules, which that calls the register command request, but if it were to error because the command is not there, it would be a pain too.

So here are some solutions off the top of my head:

  • Leave it as we have it right now +-: We already have event detection, meaning we already have the code to detect if a request has a command handler or not and we already print a warning when it's not available. I think it prints using logger.debug which is fine IMO. It doesn't pollute the logs for normal users, but if they have issues, we can ask them to using --loglevel=debug and see if something wasn't registered. Works for us too.
  • Add a param to request where you can say in which context you want to run, eg run, console, etc.: I'm not a fan of this one, because it's annoying to enter a lot of contexts
  • Add a param to request when that request is fire and forget: So if a request is not necessary for the rest of Embark to run, it could do something like: request('my:event', {optional: true});. Then we can make it so that as soon as a request doesn't have a command handler, we throw an error, but in the case of optional requests, we just log it in loglevel debug.

I prefer option 1 and 3, without a particular favorite, but you might have better options too

Thanks for your feedback @jrainville !

Example: the command to add console commands is really not a big deal if it fails, because it doesn't wait on anything and in the case of embark test, it needs the ENS modules, which that calls the register command request, but if it were to error because the command is not there, it would be a pain too.

I'm having a hard time following this one, maybe you can link to some code that illustrates what you're talking about?

On the other hand, I also know that some commands are getting called in a fire and forget manner

That's fair enough. So if we really need/want a mechanism that kicks off some computation but we don't actually care whether or not it's gonna happen, we should encode that explicitly in our APIs and handle such cases different from actual "requests".

I'm pretty sure we've discussed this in the past with @iurimatias where he tried to distinguish between things we can request, that actually return, and things that just fires off an action.

If we make these things explicit, then this could be a solution to the problem. However, that would mean that every request() should error when there's no such handler available. For anything that is indeed fire and forget, there should be a separate API that makes this explicit.

In other words:

await eventbus.request('someRegisteredAction'); // would throw if it doesn't exist

eventbus.triggerAction('someFireAndForgetAction') // would not care if the action actually exists

Notice that we also don't wait for triggerAction() (name TBD) to finish or anything, as we don't actually expect a response anyways. It might be useful though to actually wait, especially for cases like runBeforeAllAction and similar things. So maybe we can implement triggerAction() to always return a promise that either always resolves, or, can still error when any of the actions fail.

Which brings up another interesting point... if we say we have fire and forget actions.. do we care of they fail?

Notice that the above is similar to your proposed option 3, just that, instead of extending request() we'll have a different method with its own semantics.