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

Fix failures handling #95

Merged
merged 6 commits into from
Feb 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ requires-python = ">=3.12,<3.13"
description = "Make ZIM file from Kolibri Channels"
readme = "README.md"
dependencies = [
"zimscraperlib==3.3.0",
"zimscraperlib==3.3.1",
"kiwixstorage==0.8.3",
"Jinja2==3.1.3",
"pif==0.8.2",
Expand All @@ -22,7 +22,7 @@ kind = "scraper"
additional-keywords = ["kolibri"]

[tool.hatch.build.hooks.openzim-build]
dependencies = [ "zimscraperlib==3.3.0" ] # required for fix_ogv_dist
dependencies = [ "zimscraperlib==3.3.1" ] # required for fix_ogv_dist

[project.optional-dependencies]
scripts = [
Expand Down
39 changes: 24 additions & 15 deletions src/kolibri2zim/scraper.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,17 @@
return ark.open(member).read()


def wrap_failure_details(func):
def wrapper(self, item):
try:
node_id, kind = item
return func(self, item)
except Exception as exc:
raise RuntimeError(f"Failed to process {kind} node {node_id}") from exc

Check warning on line 100 in src/kolibri2zim/scraper.py

View check run for this annotation

Codecov / codecov/patch

src/kolibri2zim/scraper.py#L96-L100

Added lines #L96 - L100 were not covered by tests

return wrapper


class Kolibri2Zim:
def __init__(self, **kwargs):
for option in options:
Expand Down Expand Up @@ -179,13 +190,9 @@
def populate_nodes_executor(self):
"""Loop on content nodes to create zim entries from kolibri DB"""

def remove_future(future):
self.nodes_futures.remove(future)

def schedule_node(item):
future = self.nodes_executor.submit(self.add_node, item=item)
self.nodes_futures.add(future)
future.add_done_callback(remove_future)

# schedule root-id
schedule_node((self.db.root["id"], self.db.root["kind"]))
Expand All @@ -195,6 +202,7 @@
if self.node_ids is None or node["id"] in self.node_ids:
schedule_node((node["id"], node["kind"]))

@wrap_failure_details
def add_node(self, item):
"""process a content node from the tuple in queue"""
node_id, kind = item
Expand Down Expand Up @@ -873,7 +881,7 @@
self.populate_nodes_executor()

# await completion of all futures (nodes and videos)
result = cf.wait(
futures = cf.wait(

Check warning on line 884 in src/kolibri2zim/scraper.py

View check run for this annotation

Codecov / codecov/patch

src/kolibri2zim/scraper.py#L884

Added line #L884 was not covered by tests
self.videos_futures | self.nodes_futures,
return_when=cf.FIRST_EXCEPTION,
)
Expand All @@ -883,19 +891,20 @@
# only awaits future completion and doesn't include callbacks
self.videos_executor.shutdown()

succeeded = (
not result.not_done
and sum([1 if fs.exception() else 0 for fs in result.done]) == 0
nb_done_with_failure = sum(
1 if future.exception() else 0 for future in futures.done
)
succeeded = not futures.not_done and nb_done_with_failure == 0

Check warning on line 897 in src/kolibri2zim/scraper.py

View check run for this annotation

Codecov / codecov/patch

src/kolibri2zim/scraper.py#L897

Added line #L897 was not covered by tests

# DEBUG: raise first exception
if not succeeded and result.done:
logger.info(
f"FAILURE not_done={len(result.not_done)} done={len(result.done)}"
if not succeeded:
logger.warning(

Check warning on line 900 in src/kolibri2zim/scraper.py

View check run for this annotation

Codecov / codecov/patch

src/kolibri2zim/scraper.py#L900

Added line #L900 was not covered by tests
f"FAILURE: not_done={len(futures.not_done)}, "
f"done successfully={len(futures.done) - nb_done_with_failure}, "
f"done with failure={nb_done_with_failure}"
)
for future in result.done:
if future.exception():
raise future.exception() # pyright:ignore
for future in [fut for fut in futures.done if fut.exception()]:
logger.warning("", exc_info=future.exception())
raise Exception("Some nodes have not been processed successfully")

Check warning on line 907 in src/kolibri2zim/scraper.py

View check run for this annotation

Codecov / codecov/patch

src/kolibri2zim/scraper.py#L906-L907

Added lines #L906 - L907 were not covered by tests
except KeyboardInterrupt:
self.creator.can_finish = False
logger.error("KeyboardInterrupt, exiting.")
Expand Down
Loading