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

10.0 dev reload with inotify #31855

Closed
wants to merge 4 commits into from

Conversation

Icallhimtest
Copy link
Contributor

Add the alternative of inotify instead of watchdog to watch the addons path the server was started with.

Reason: watchdog spawns 2 threads per path to watch. When there are a lot of addons paths, this can become too costly. With inotify we watch all the repositories in a single thread.

https://github.com/dsoprea/PyInotify

installation:
pip install inotify

This PR is a bit more dirty than what's suggested in https://github.com/odoo-dev/odoo/tree/10.0-dev-reload-dve but a lot more efficient.

Python2 uses IOError instead.

/!\ DO NOT FORWARD PORT AFTER 11.* /!\
Before this commit every worker would start his own FSWatcher.
@Icallhimtest Icallhimtest changed the title 10.0 dev reload dve 10.0 dev reload with inotify Mar 14, 2019
@C3POdoo C3POdoo added the RD research & development, internal work label Mar 14, 2019
@robodoo robodoo added the CI 🤖 Robodoo has seen passing statuses label Mar 14, 2019
if 'reload' in config['dev_mode']:
if watchdog:
if 'reload' in config['dev_mode'] and not odoo.evented:
if inotify and not odoo.evented:
Copy link
Contributor

Choose a reason for hiding this comment

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

check on odoo.evented is useless (already checked the line before)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

whoops, indeed

if not self.watcher:
self.watcher = InotifyTree(path, mask=INOTIFY_LISTEN_EVENTS, block_duration_s=1.0)
else:
self.watcher._InotifyTree__load_tree(path)
Copy link
Contributor

Choose a reason for hiding this comment

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

Ho yes, it's dirty

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, But this avoids having to iterate through different InotifyTree and have all the events on a single fd, which, on my 500 addons-paths test prevents a constant 2% CPU usage to iterate on every path every second.

while self.started:
for event in self.watcher.event_gen(timeout_s=0, yield_nones=False):
(_, type_names, path, filename) = event
if filename.endswith('.py') and not filename.startswith('.~') and 'IN_ISDIR' not in type_names:
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you extract this block inside a common function with FSWatcher using a common ancestor?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

will do

if os.name == 'posix':
module = 'inotify'
else:
module = 'Watchdog'
Copy link
Contributor

Choose a reason for hiding this comment

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

lowercase

watcher = FSWatcher()
watcher.start()
else:
_logger.warning("'watchdog' module not installed. Code autoreload feature is disabled")
if os.name == 'posix':
Copy link
Contributor

Choose a reason for hiding this comment

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

there is not inotify on osx. watchdog is still needed

@robodoo robodoo removed the CI 🤖 Robodoo has seen passing statuses label Mar 15, 2019
@Icallhimtest
Copy link
Contributor Author

@KangOl @antonylesuisse
The FSWatcherInotify runs fine for the expected scenarios, but a few questions remain:

  1. Inotify behaves a bit differently when moving folders containing files than watchdog. Watchdog will give the notifications for each file in the folder, while inotify only gives the folder move event (I believe because the files get created before inotify gets a chance to add the folder to its watchlist, not sure how watchdog handles this). The question becomes:

a) Do we automatically reload upon directory moves?
b) Do we os.walk the directory in search of python files and reload only if it contains one & it compiles?
c) Do we ignore them? <-- current implementation

  1. Current watchdog implementation ignores when we delete or move a file away from the folder, even a python file.

Is this intended behaviour? Current inotify implementation copies this. It doesn't listen to IN_DELETE, IN_DELETE_SELF, IN_MOVE_SELF, IN_MOVED_FROM events. ( http://man7.org/linux/man-pages/man7/inotify.7.html )

  1. Is it ok to use the __load_tree method from the InotifyTree object? Its signature hasn't changed since its addition 4 years ago. https://github.com/dsoprea/PyInotify/blame/master/inotify/adapters.py#L342

@robodoo robodoo added the CI 🤖 Robodoo has seen passing statuses label Mar 15, 2019
@KangOl
Copy link
Contributor

KangOl commented Mar 15, 2019 via email

@Icallhimtest
Copy link
Contributor Author

@KangOl whoops, good thing you saw the InotifyTrees class, I completely missed it. It'll be nice & clean this way.

For point 1, looking at watchdog, they generate all the events manually when a directory is created:

https://github.com/gorakhargosh/watchdog/blob/master/src/watchdog/observers/inotify.py#L156
https://github.com/gorakhargosh/watchdog/blob/master/src/watchdog/events.py#L612

I'm hesitating between submitting a PR to inotify adding this feature somewhere here https://github.com/dsoprea/PyInotify/blame/master/inotify/adapters.py#L287
or simply doing it in Odoo.

@robodoo robodoo removed the CI 🤖 Robodoo has seen passing statuses label Mar 15, 2019
@KangOl
Copy link
Contributor

KangOl commented Mar 15, 2019

From the reactivity of maintainer of pyinotify, it's better to handle it inside odoo, even if a PR is made upstream.

@Icallhimtest Icallhimtest force-pushed the 10.0-dev-reload-dirty-dve branch 2 times, most recently from 24940af to ecbb498 Compare March 15, 2019 13:47
@robodoo robodoo added the CI 🤖 Robodoo has seen passing statuses label Mar 15, 2019
Add the alternative of inotify instead of watchdog to watch the addons
paths the server was started with.

Reason: watchdog spawns 2 threads per path to watch. When there are a
lot of addons paths, this can become too costly. With inotify we watch
all the repositories in a single thread.

https://github.com/dsoprea/PyInotify

installation:

    pip install inotify
Avoid potential tracebacks from the FSWatcher's thread being killed.

Drawback: Server shut down can have an extra small delay

(only applies when the --dev=reload option is given)
@robodoo robodoo removed the CI 🤖 Robodoo has seen passing statuses label Mar 15, 2019
@Icallhimtest
Copy link
Contributor Author

@KangOl alrighty,

1b) applied & tested on my end
2) kept same as watchdog
3) done

Should be good to go.

@antonylesuisse
Copy link
Contributor

Make sure it also works for editor that write in place.

@Icallhimtest
Copy link
Contributor Author

@antonylesuisse Yeah, it does.

It listens to IN_WRITE or IN_MOVED_TO events. (+ IN_CREATE)

Both swapping or writing in place are covered by this.

@Icallhimtest
Copy link
Contributor Author

@KangOl Want any more changes or are we good to go here?

Copy link
Contributor

@KangOl KangOl left a comment

Choose a reason for hiding this comment

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

@robodoo rebase-ff r+

@robodoo
Copy link
Contributor

robodoo commented Mar 20, 2019

Merge method set to rebase and fast-forward

robodoo pushed a commit that referenced this pull request Mar 20, 2019
Avoid potential tracebacks from the FSWatcher's thread being killed.

Drawback: Server shut down can have an extra small delay

(only applies when the --dev=reload option is given)

closes #31855

Signed-off-by: Christophe Simonis <chs@odoo.com>
@robodoo robodoo added CI 🤖 Robodoo has seen passing statuses merging 👷 and removed merging 👷 labels Mar 20, 2019
@robodoo
Copy link
Contributor

robodoo commented Mar 20, 2019

Merged, thanks!

@robodoo robodoo closed this Mar 20, 2019
@odony odony deleted the 10.0-dev-reload-dirty-dve branch March 25, 2019 12:42
remihb pushed a commit to osiell/OCB that referenced this pull request Mar 28, 2019
Avoid potential tracebacks from the FSWatcher's thread being killed.

Drawback: Server shut down can have an extra small delay

(only applies when the --dev=reload option is given)

closes odoo#31855

Signed-off-by: Christophe Simonis <chs@odoo.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CI 🤖 Robodoo has seen passing statuses RD research & development, internal work
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants