tcalmant / ipopo

iPOPO: a Service-Oriented Component Model for Python
https://ipopo.readthedocs.io/
Apache License 2.0
69 stars 28 forks source link

Retry validation if it fails #103

Closed LibertyWalk closed 4 years ago

LibertyWalk commented 5 years ago

I have a consumer, which commands its provider to connect to a server. This server might not be online at the point in the the iPOPO bundle is started. This, of course, invalidates the consumer and stops it from ever being executed without restarting the whole bundle. First off, I'm not sure about the purpose of @Validate. Is this supposed to validate the consumer, if all its prerequisites (like the server connection) are valid? Or is it just, like the docs say, for validating that all of its required dependencies (like for example its provider) have been injected? Second, is there a mechanism for trying to validate a component until it succeeds, instead of just declaring it as invalidated? I tried to do that in the @Validate function of my consumer. The consumer commanded the provider to try to connect to the server until it succeeds in doing so, but when the connection finally succeeded, a TimeOutError was thrown inside of the @Validate of the consumer.

Is something like waiting for a connection even compatible with iPOPO?

Thanks for developing this project.

fijemax commented 5 years ago

I did someting like it for a websocket handler. The websocket handler bundle must provide his service only when the websocket connexion is available.

To provide a service manually:

Do not use the @Provides annotation

First save the contexte handler you received in the validate method

    @Validate
    def validate(self, context):
        self._context = context

Create two methods to register and unregister you service:

    def _register_service(self):
        self.logger.info('WebsocketHandler service validated')
        if not self._service_registration:
            self._service_registration = self._context.register_service(
                "websocket_handler_service", self, {})

    def _unregister_service(self):
        if self._service_registration:
            self.logger.info('WebsocketHandler service invalidated')
            self._context.get_framework().unregister_service(
                self._service_registration)
            self._service_registration = None

You simply need to call _register_service or _unregister_service when you want provide your service or not. In my my case when websocket are available the service is registered and all dependent services are notifyed or validated.

websocket_handler_service is the name to require in others bundles

fijemax commented 5 years ago

The documentation: https://ipopo.readthedocs.io/en/0.8.1/refcards/services.html?highlight=register_service

fijemax commented 5 years ago

A websocket handler sample

sample.zip

tcalmant commented 5 years ago

Hi,

Like @fijemax said, your provider must be an instantiated component that registers the service your consumer requires. Unlink most component models, where required components are spawned automatically by the framework; in iPOPO you have to instantiate both the consumer and the provider with their configuration. The provider will have to indicate if it provides the service or not (like in @fijemax example).

That being said, I'll just add some notes:

Note that a lot of stuff is done when changing the value of the flag (calls register_service(), notifies listeners, possibly in/validates components, ...).

tcalmant commented 5 years ago

Also, to reply to the original question:

This has to be done manually, as the exception means there is something wrong either with the code, the configuration or an injected service. Note that you you should be able to call retry_erroneous() from the component itself, in an BindField callback (but I never tried it as it seems more like a last-resort trick)