Issue with db-relation-changed hook in Operator framework

Hello,
My goal is to write an operator charm that relates to the mysql charm. Retrieves the info from the event to write the config to my external application and then start the application. Last I would like to let the user know that the application has started and that is where I’m running into my issue.

After I set the status that the application has started. the db-relationship-changed hook fires again and sets the status to db related instead of application started, what I want it to be.

unit-foo-4: 22:16:47 DEBUG unit.foo/4.juju-log db:42: Emitting Juju event db_relation_changed.
unit-foo-4: 22:16:48 INFO unit.foo/4.juju-log db:42: inside of foo
unit-foo-4: 22:16:48 INFO unit.foo/4.juju-log db:42: start application
unit-foo-4: 22:16:49 INFO unit.foo/4.juju-log db:42: Ath7cea0ishiec7
unit-foo-4: 22:16:50 INFO juju.worker.uniter.operation ran "db-relation-changed" hook

Main charm code


class FooCharm(CharmBase):
    bar = Bar
    def __init__(self, *args):
        super().__init__(*args)

        self._bar = self.bar(self, 'bar')
        self.db = MySQLClient(self, 'db')

        self.framework.observe(
            self.db.on.database_available,
            self._on_database_available
        )
        self.framework.observe(
            self._bar.on.config_changed,
            self._on_config_changed
        )

    def _on_database_available(self, event):
        self._bar.foo()
        self.unit.status = ActiveStatus("db related")

    def _on_config_changed(self, event):
        logger.info("start application")
        self.unit.status = ActiveStatus("application started")

external resource handler

class ConfigChangedEvent(EventBase):
    def __init__(self, handle):
        super().__init__(handle)
        self.config = True  
         
    def is_configured(self):
        return self.config  
        
class BarEvents(ObjectEvents):
    config_changed = EventSource(ConfigChangedEvent)

class Bar(Object):
    on = BarEvents()
    
    def __init__(self, charm, key):
        super().__init__(charm, key)
    
    def foo(self):
       logger.info("inside of foo")
       self.on.config_changed.emit()

My wish is to have the code inside _on_database_available run only once. I was wondering what the best way to implement that in the operator framework. I hope this can open up a discussion of how to implement hooks most effectively in the new operator framework

here is the full repo: https://github.com/ducks23/charm-foo

to replicate:

git clone https://github.com/ducks23/charm-foo

cd charm-foo
git sumbodule init
git submodule update
juju deploy .
juju deploy mysql
juju relate mysql:db foo:db

Thanks

1 Like