Hot Reload#

While developing your Executor, it can be useful to have the Executor be refreshed from the source code while you are working on it, without needing to restart the Flow server.

For this you can use the Executor’s reload argument to watch changes in the source code and the Executor YAML configuration and ensure changes are applied to the served Executor.

The Executor will keep track of changes inside the Executor source and YAML files, every file passed in py_modules argument from add() and all the Python files in the Executor’s folder and sub-folders).

Caution

This feature is thought to let the developer iterate faster while developing or improving the Executor, but is not intended to be used in production environment.

Note

This feature requires watchfiles>=0.18 package to be installed.

To see how this would work, let’s have an Executor defined in a file my_executor.py

from jina import Executor, requests


class MyExecutor(Executor):
    @requests
    def foo(self, docs, **kwargs):
        for doc in docs:
            doc.text = 'I am coming from the first version of MyExecutor'

We build a Flow and expose it:

import os
from jina import Flow

from my_executor import MyExecutor

os.environ['JINA_LOG_LEVEL'] = 'DEBUG'


f = Flow(port=12345).add(uses=MyExecutor, reload=True)

with f:
    f.block()

We can see that the Executor is successfuly serving:

from jina import Client, DocumentArray

c = Client(port=12345)

print(c.post(on='/', inputs=DocumentArray.empty(1))[0].text)
I am coming from the first version of MyExecutor

We can edit the executor file and save the changes:

from jina import Executor, requests


class MyExecutor(Executor):
    @requests
    def foo(self, docs, **kwargs):
        for doc in docs:
            doc.text = 'I am coming from a new version of MyExecutor'

You should see in the logs of the serving Executor

INFO   executor0/rep-0@11606 detected changes in: ['XXX/XXX/XXX/my_executor.py']. Refreshing the Executor                                                             

And after this, Executor will start serving with the renewed code.

from jina import Client, DocumentArray

c = Client(port=12345)

print(c.post(on='/', inputs=DocumentArray.empty(1))[0].text)
'I am coming from a new version of MyExecutor'

Reloading is also applied when the Executor’s YAML configuration file is changed. In this case, the Executor deployment restarts.

To see how this works, let’s define an Executor configuration in executor.yml:

jtype: MyExecutorBeforeReload

Build a Flow with the Executor in it and expose it:

import os
from jina import Flow, Executor, requests

os.environ['JINA_LOG_LEVEL'] = 'DEBUG'


class MyExecutorBeforeReload(Executor):
    @requests
    def foo(self, docs, **kwargs):
        for doc in docs:
            doc.text = 'MyExecutorBeforeReload'


class MyExecutorAfterReload(Executor):
    @requests
    def foo(self, docs, **kwargs):
        for doc in docs:
            doc.text = 'MyExecutorAfterReload'


f = Flow(port=12345).add(uses='executor.yml', reload=True)

with f:
    f.block()

You can see that the Executor is running and serving:

from jina import Client, DocumentArray

c = Client(port=12345)

print(c.post(on='/', inputs=DocumentArray.empty(1))[0].text)
MyExecutorBeforeReload

You can edit the Executor YAML file and save the changes:

jtype: MyExecutorAfterReload

In the Flow’s logs you should see:

INFO   Flow@1843 change in Executor configuration YAML /home/joan/jina/jina/exec.yml observed, restarting Executor deployment  

And after this, you can see the reloaded Executor being served:

from jina import Client, DocumentArray

c = Client(port=12345)

print(c.post(on='/', inputs=DocumentArray.empty(1))[0].text)
jtype: MyExecutorAfterReload