Skip to content

Commit

Permalink
WIP racing conditions
Browse files Browse the repository at this point in the history
  • Loading branch information
mpvanderschelling committed Feb 7, 2025
1 parent 8aceeea commit 838eea3
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 11 deletions.
9 changes: 6 additions & 3 deletions src/f3dasm/_src/design/domain.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
from omegaconf import DictConfig, OmegaConf

# Local
from ..errors import EmptyFileError
from ..errors import DecodeError, EmptyFileError
from .parameter import (CategoricalParameter, CategoricalType,
ConstantParameter, ContinuousParameter,
DiscreteParameter, LoadFunction, Parameter,
Expand Down Expand Up @@ -203,8 +203,11 @@ def from_file(cls: Type[Domain], filename: Path | str) -> Domain:
if filename.stat().st_size == 0:
raise EmptyFileError(filename)

with open(filename, 'r') as f:
domain_dict = json.load(f)
try:
with open(filename, 'r') as f:
domain_dict = json.load(f)
except json.JSONDecodeError:
raise DecodeError(filename)

input_space = {k: Parameter.from_dict(
v) for k, v in domain_dict['input_space'].items()}
Expand Down
34 changes: 34 additions & 0 deletions src/f3dasm/_src/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,37 @@ def __init__(self, file_path: str | Path, message: str = "File is empty"):
self.file_path = Path(file_path) # Ensure it's a Path object
self.message = f"{message}: {self.file_path}"
super().__init__(self.message)


class DecodeError(Exception):
"""Exception raised when opening a file gives errors"""

def __init__(self, file_path: str | Path,
message: str = "Error decoding file"):
"""
Initializes the EmptyFileError.
Args:
file_path (str | Path): The path to faulty file.
message (str): A custom error message.
"""
self.file_path = Path(file_path) # Ensure it's a Path object
self.message = f"{message}: {self.file_path}"
super().__init__(self.message)


class ReachMaximumTriesError(Exception):
"""Exception raised when a function reaches its maximum number of tries."""

def __init__(self, file_path: str | Path, max_tries: int,
message: str = "Reached maximum number of tries"):
"""
Initializes the ReachMaximumTriesError.
Args:
max_tries (int): The maximum number of tries.
message (str): A custom error message.
"""
self.max_tries = max_tries
self.message = f"{message} for {file_path}: {self.max_tries}"
super().__init__(self.message)
24 changes: 16 additions & 8 deletions src/f3dasm/_src/experimentdata.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
from .core import Block, DataGenerator
from .datageneration import _datagenerator_factory
from .design import Domain, _domain_factory, _sampler_factory
from .errors import EmptyFileError
from .errors import DecodeError, EmptyFileError, ReachMaximumTriesError
from .experimentsample import ExperimentSample
from .logger import logger
from .optimization import _optimizer_factory
Expand Down Expand Up @@ -300,7 +300,7 @@ def wrapper_func(project_dir: Path, *args, **kwargs) -> None:
# If the lock has been acquired:
with lock:
tries = 0
while tries < MAX_TRIES:
while tries <= MAX_TRIES:
try:
# Load a fresh instance of ExperimentData from file
loaded_self = ExperimentData.from_file(
Expand All @@ -314,14 +314,15 @@ def wrapper_func(project_dir: Path, *args, **kwargs) -> None:
break
# Racing conditions can occur when the file is empty
# and the file is being read at the same time
except EmptyFileError:
except (EmptyFileError, DecodeError):
tries += 1
logger.debug((
f"EmptyDataError occurred, retrying"
f"Error reading a file, retrying"
f" {tries+1}/{MAX_TRIES}"))
sleep(random.uniform(0.5, 2.5))

raise EmptyFileError(self.project_dir)
raise ReachMaximumTriesError(file_path=self.project_dir,
max_tires=tries)

return value

Expand Down Expand Up @@ -1664,7 +1665,10 @@ def _dict_factory(data: pd.DataFrame | List[Dict[str, Any]] | None | Path | str
if filepath.stat().st_size == 0:
raise EmptyFileError(filepath)

df = pd.read_csv(filepath, header=0, index_col=0)
try:
df = pd.read_csv(filepath, header=0, index_col=0)
except pd.errors.EmptyDataError:
raise DecodeError(filepath)

return _dict_factory(df)

Expand Down Expand Up @@ -1752,8 +1756,12 @@ def jobs_factory(jobs: pd.Series | str | Path | None) -> pd.Series:
if filepath.stat().st_size == 0:
raise EmptyFileError(filepath)

df = pd.read_csv(filepath,
header=0, index_col=0).squeeze()
try:
df = pd.read_csv(filepath,
header=0, index_col=0).squeeze()
except pd.errors.EmptyDataError:
raise DecodeError(filepath)

# If the jobs is jut one value, it is parsed as a string
# So, make sure that we return a pd.Series either way!
if not isinstance(df, pd.Series):
Expand Down

0 comments on commit 838eea3

Please sign in to comment.