Skip to content

Finish precaching, background updates, and placeholder items#98

Merged
drinfernoo merged 109 commits into
developfrom
handle_errors
Sep 6, 2021
Merged

Finish precaching, background updates, and placeholder items#98
drinfernoo merged 109 commits into
developfrom
handle_errors

Conversation

@drinfernoo
Copy link
Copy Markdown
Owner

This PR builds on code from #76, and largely covers precaching of paths which will be displayed in the future, like "Next Page" paths and others in the same Cycling Widget. It also adds three "placeholder" items that can appear during widget load:

  • "Loading content..." for when a widget is... loading content 😅
  • "No content found for X" for when no items are returned for a particular path
  • "Error showing X" for when the response for a path is invalid in some way

This PR also ensures that we don't save an invalid cache for the latter case, and adds some notifications about various background processes, like exploding paths and updating widgets in the background.

djay and others added 30 commits July 18, 2021 16:32
props=properties,
)
# Ensure we precache next page for faster access
cache.cache_expiry(file["file"], widget_id, background=True)
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Here's the magic of pre-caching a "Next Page" item.

props=properties,
)
# Ensure we precache next page for faster access
cache.cache_expiry(file["file"], widget_id)
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Here's the magic where we pre-cache the next page.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think this means a precached next page is going to cause an unneeded widget redraw. Pass some flag in teh queue file to say not to refresh the widget if its a precache?

return titles if titles else True, path_label, content

utils.log("Loading items from {}".format(path), "debug")
files, hash = refresh.get_files_list(path, path_label, widget_id)
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Passing path_label through this allows us to properly label the placeholder tiles.

) # Just in queued path's widget defintion has changed and it didn't update this path
unrefreshed_widgets = unrefreshed_widgets.union(
effected_widgets
affected_widgets
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Had to fix these 😉

hash, widget_ids = queue.pop(0)
utils.log("Dequeued cache update: {}".format(hash[:5]), "notice")

affected_widgets = cache.cache_and_update(
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

This bit right here makes sure to cache any queued paths any time they show up.

def get_files_list(path, widget_id=None):
hash = utils.path2hash(path)
_, files, _ = utils.cache_expiry(hash, widget_id)
def get_files_list(path, label=None, widget_id=None, background=True):
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

We always do caching in the background, except in the case of exploding/cloning.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I was thinking next page should not be done in the background but I guess if its always precached then this is no longer a problem

# Should only happen now when background is False
utils.log("Blocking cache path read: {}".format(hash[:5]), "info")
files, changed = utils.cache_files(path, widget_id)
files, changed = cache.cache_files(path, widget_id)
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Create a cache for the path if there isn't one already.

else:
utils.log("Error processing {}".format(hash), "error")
return None, hash
error_tile = utils.make_holding_path(
Copy link
Copy Markdown
Owner Author

@drinfernoo drinfernoo Jul 23, 2021

Choose a reason for hiding this comment

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

Create an "error state" tile if the JSON response in the existing cache file is invalid in some way.

cache_path = os.path.join(_addon_data, "{}.cache".format(hash))
if os.path.exists(cache_path):
os.remove(cache_path)
utils.log("Invalid cache file removed for {}".format(hash))
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

If that is the case, we'll go ahead and remove that cache file now, so that we don't hold an invalid cache.


if not files:
utils.log("No items found for {}".format(hash))
empty_tile = utils.make_holding_path(
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

If the cache is valid, but there are no files to return, then we make an "empty path" tile instead.

for file in files:
new_file = {k: v for k, v in file.items() if v is not None}

def queue_widget_update(widget_id):
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

It didn't seem that this method was actually used anywhere, so I just got rid of it again.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

yes. original way I tried to do queues. not used anymore but useful to know there is another way to communicate with the service process

Copy link
Copy Markdown
Owner Author

@drinfernoo drinfernoo left a comment

Choose a reason for hiding this comment

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

@djay I've commented up the PR a bit, so you can check and see if you think my changes are reasonable 👍

msgstr "No content found for {}"

#: /resources/lib/refresh.py:95
msgctxt "#30141"
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

I "viewed" all of the other .po files, but these are the new translations I added.

@drinfernoo
Copy link
Copy Markdown
Owner Author

The other thing that sticks out to me a lot in this code is that there are a lot of leftover commented bits and "todos", but those should probably be tackled in a further "refactor" PR focused on performance and flexibility of these caching processes.

@drinfernoo drinfernoo force-pushed the develop branch 2 times, most recently from a905d44 to 9542859 Compare July 26, 2021 12:25
@djay
Copy link
Copy Markdown
Collaborator

djay commented Aug 2, 2021

I should probably go through the TODOs. Often they get fixed later somewhere else I forget I had a TODO for it.
e.g. I think this might be handled by your precache code right? on refresh a next cycled path is precached?

    # TODO: update paths on autowidget refresh based on predicted update frequency. e.g. plugins with random paths should
    # update when autowidget updates.

Some other TODOs might be better moved to github feature requests. Like periodic caching cleaning to reduce space.

I think most of the rest of the TODOs are around estimating how long to cache a path, or the likelyhood of a path needing updating after playback. Not sure if these are enabled in the latest code?

@drinfernoo
Copy link
Copy Markdown
Owner Author

drinfernoo commented Aug 10, 2021

I should probably go through the TODOs. Often they get fixed later somewhere else I forget I had a TODO for it.
e.g. I think this might be handled by your precache code right? on refresh a next cycled path is precached?

    # TODO: update paths on autowidget refresh based on predicted update frequency. e.g. plugins with random paths should
    # update when autowidget updates.

Some other TODOs might be better moved to github feature requests. Like periodic caching cleaning to reduce space.

I think most of the rest of the TODOs are around estimating how long to cache a path, or the likelyhood of a path needing updating after playback. Not sure if these are enabled in the latest code?

So, refreshing after playback is included in this PR, but it should also be in master as well. I'm honestly not sure if it's really working the way it should, especially with regards to the "forensic" caching you've got in here... but I'm going to say we can tackle that at a later date.

I'd like to go ahead and merge this in soon, and start looking at some other potential refactoring and performance increases for a future major update, which will likely include some of those caching mechanisms.

Also, for what it's worth, this PR moves most all of the caching stuff to cache.py for organization, so hopefully future maintenance of the caching system will be a little bit easier.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

2 participants