Skip to content

Commit 55ddf2f

Browse files
author
Cody Baker
committed
added exponential retry
1 parent 9586da0 commit 55ddf2f

File tree

1 file changed

+43
-25
lines changed

1 file changed

+43
-25
lines changed

nwbinspector/nwbinspector.py

Lines changed: 43 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from types import FunctionType
1414
from warnings import filterwarnings, warn
1515
from distutils.util import strtobool
16+
from time import sleep
1617

1718
import click
1819
import pynwb
@@ -153,10 +154,7 @@ def configure_checks(
153154
@click.argument("path")
154155
@click.option("--modules", help="Modules to import prior to reading the file(s).")
155156
@click.option(
156-
"--report-file-path",
157-
default=None,
158-
help="Save path for the report file.",
159-
type=click.Path(writable=True),
157+
"--report-file-path", default=None, help="Save path for the report file.", type=click.Path(writable=True),
160158
)
161159
@click.option("--overwrite", help="Overwrite an existing report file at the location.", is_flag=True)
162160
@click.option("--levels", help="Comma-separated names of InspectorMessage attributes to organize by.")
@@ -411,8 +409,9 @@ def inspect_nwb(
411409
ignore: OptionalListOfStrings = None,
412410
select: OptionalListOfStrings = None,
413411
importance_threshold: Importance = Importance.BEST_PRACTICE_SUGGESTION,
414-
driver: str = None,
412+
driver: Optional[str] = None,
415413
skip_validate: bool = False,
414+
max_retries: int = 10,
416415
) -> List[InspectorMessage]:
417416
"""
418417
Inspect a NWBFile object and return suggestions for improvements according to best practices.
@@ -446,6 +445,11 @@ def inspect_nwb(
446445
skip_validate : bool
447446
Skip the PyNWB validation step. This may be desired for older NWBFiles (< schema version v2.10).
448447
The default is False, which is also recommended.
448+
max_retries : int, optional
449+
When using the ros3 driver to stream data from an s3 path, occasional curl issues can result.
450+
AWS suggests using iterative retry with an exponential backoff of 0.1 * 2^retries.
451+
This sets a hard bound on the number of times to attempt to retry the collection of messages.
452+
Defaults to 10 (corresponds to 102.4s maximum delay on final attempt).
449453
"""
450454
if any(x is not None for x in [config, ignore, select, importance_threshold]):
451455
checks = configure_checks(
@@ -454,30 +458,44 @@ def inspect_nwb(
454458
nwbfile_path = str(nwbfile_path)
455459
filterwarnings(action="ignore", message="No cached namespaces found in .*")
456460
filterwarnings(action="ignore", message="Ignoring cached namespace .*")
457-
with pynwb.NWBHDF5IO(path=nwbfile_path, mode="r", load_namespaces=True, driver=driver) as io:
458-
if not skip_validate:
459-
validation_errors = pynwb.validate(io=io)
460-
for validation_error in validation_errors:
461+
462+
def _collect_all_messages(nwbfile_path: FilePathType, driver: Optional[str] = None, skip_validate: bool = False):
463+
with pynwb.NWBHDF5IO(path=nwbfile_path, mode="r", load_namespaces=True, driver=driver) as io:
464+
if not skip_validate:
465+
validation_errors = pynwb.validate(io=io)
466+
for validation_error in validation_errors:
467+
yield InspectorMessage(
468+
message=validation_error.reason,
469+
importance=Importance.PYNWB_VALIDATION,
470+
check_function_name=validation_error.name,
471+
location=validation_error.location,
472+
file_path=nwbfile_path,
473+
)
474+
475+
try:
476+
nwbfile = io.read()
477+
for inspector_message in run_checks(nwbfile=nwbfile, checks=checks):
478+
inspector_message.file_path = nwbfile_path
479+
yield inspector_message
480+
except Exception as ex:
461481
yield InspectorMessage(
462-
message=validation_error.reason,
463-
importance=Importance.PYNWB_VALIDATION,
464-
check_function_name=validation_error.name,
465-
location=validation_error.location,
482+
message=traceback.format_exc(),
483+
importance=Importance.ERROR,
484+
check_function_name=f"During io.read() - {type(ex)}: {str(ex)}",
466485
file_path=nwbfile_path,
467486
)
468487

469-
try:
470-
nwbfile = io.read()
471-
for inspector_message in run_checks(nwbfile=nwbfile, checks=checks):
472-
inspector_message.file_path = nwbfile_path
473-
yield inspector_message
474-
except Exception as ex:
475-
yield InspectorMessage(
476-
message=traceback.format_exc(),
477-
importance=Importance.ERROR,
478-
check_function_name=f"During io.read() - {type(ex)}: {str(ex)}",
479-
file_path=nwbfile_path,
480-
)
488+
if driver != "ros3":
489+
yield _collect_all_messages(nwbfile_path=nwbfile_path, driver=driver, skip_validate=skip_validate)
490+
else:
491+
retries = 0
492+
493+
while retries < max_retries:
494+
try:
495+
retries += 1
496+
yield _collect_all_messages(nwbfile_path=nwbfile_path, driver=driver, skip_validate=skip_validate)
497+
except OSError: # Cannot curl request
498+
sleep(0.1 * 2 ** retries)
481499

482500

483501
def run_checks(nwbfile: pynwb.NWBFile, checks: list):

0 commit comments

Comments
 (0)