Skip to content

Commit

Permalink
be more careful when opening files for reading; and if there is an er…
Browse files Browse the repository at this point in the history
…ror, propagate it all the way up to web interface
  • Loading branch information
atiselsts committed Mar 6, 2019
1 parent 079391b commit 2c2e5d5
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 25 deletions.
18 changes: 12 additions & 6 deletions source/g.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,8 +204,11 @@ def log(loglevel, msg):
msg += "\n"
sys.stderr.write(msg)
if logFileName is not None:
with open(logFileName, "a+") as f:
f.write(msg)
try:
with open(logFileName, "a+") as f:
f.write(msg)
except Exception as ex:
print("Got an exception while trying to write to log file: {}".format(ex))

################################################
# Startup
Expand Down Expand Up @@ -247,10 +250,13 @@ def prepare(configFileName):
logFileName = os.path.join(workDir, "spacescanner.log")

# update the log file
with open(logFileName, "a+") as f:
f.write("============= ")
f.write(spacescannerStartTime)
f.write("\n")
try:
with open(logFileName, "a+") as f:
f.write("============= ")
f.write(spacescannerStartTime)
f.write("\n")
except Exception as ex:
print("Got an exception while preparing log file: {}".format(ex))

try:
# copy the used configuration file as a reference
Expand Down
4 changes: 3 additions & 1 deletion source/job.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ def __init__(self, pool, params, maxCores, areParametersChangeable):
self.bestOfValueAfter3Sec = None
# wait this much seconds for other runners to terminate after the first one
self.waitForTerminationSec = 10
self.errorMsg = ""


def getFullName(self):
Expand Down Expand Up @@ -117,7 +118,8 @@ def createRunners(self):
for id in range(int(g.getConfig("optimization.runsPerJob"))):
r = runner.Runner(self, id + 1, self.currentMethod, self.runnerGeneration)
if not r.prepare(self.workDir, self.copasiFile, bestParams):
g.log(LOG_ERROR, "{}: failed to create a runner".format(r.getName()))
g.log(LOG_ERROR, "{}: failed to create a runner: {}".format(r.getName(), r.errorMsg))
self.errorMsg = r.errorMsg
return False
self.runners.append(r)

Expand Down
7 changes: 6 additions & 1 deletion source/jobpool.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ def __init__(self, strategy, parameterSets, areParametersChangeable):
self.maxNumParallelJobs = int(math.ceil(float(self.numUsableCores) / self.numRunnersPerJob))
self.bestOfValue = strategy.getInitialOfValue()
self.bestParams = []
self.errorMsg = ""

def start(self):
# try to start n jobs at once
Expand Down Expand Up @@ -82,7 +83,11 @@ def nextJob(self):

# execute the job
if not j.execute(g.workDir, self.strategy.copasiFile):
g.log(LOG_DEBUG, "failed to execute {}".format(j.getName()))
g.log(LOG_ERROR, "failed to execute {}: {}".format(j.getName(), j.errorMsg))
if self.errorMsg == "":
self.errorMsg = j.errorMsg
elif j.errorMsg != "":
self.errorMsg += "\n" + j.errorMsg
self.finishJob(j)

# while the number is not under the limit, wait for some job to terminate
Expand Down
30 changes: 23 additions & 7 deletions source/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ def __init__(self, job, id, methodName, generation):
self.reportFilename = None
self.copasiFile = None
self.generation = generation
self.errorMsg = ""

def getFullName(self):
return self.job.getFullName() + "/{} (method '{}')".format(
Expand All @@ -105,6 +106,7 @@ def getName(self):
self.id, self.methodName)

def prepare(self, workDir, copasiFile, startParamValues):
self.errorMsg = ""
filename = "job{}_runner{}".format(self.job.id, self.id)

# Use separate directory for each run to avoid too many files per directory
Expand All @@ -119,9 +121,17 @@ def prepare(self, workDir, copasiFile, startParamValues):
self.inputFilename = os.path.join(dirname, "input_" + filename + ".cps")
self.reportFilename = os.path.join(dirname, "output_" + filename + ".log")
self.copasiFile = copasiFile
if not copasiFile.createCopy(self.inputFilename, self.reportFilename,
self.job.params, [self.methodName], startParamValues,
self.job.areParametersChangeable):

try:
ok = copasiFile.createCopy(self.inputFilename, self.reportFilename,
self.job.params, [self.methodName], startParamValues,
self.job.areParametersChangeable)
except Exception as ex:
self.errorMsg = "cannot copy the model file {}: {}".format(self.inputFilename, ex)
g.log(LOG_ERROR, self.errorMsg)
ok = False

if not ok:
return False

# rename the old report file, if any expected
Expand All @@ -139,7 +149,8 @@ def prepare(self, workDir, copasiFile, startParamValues):

copasiExe = os.path.join(COPASI_DIR, COPASI_EXECUTABLE)
if not isExecutable(copasiExe):
g.log(LOG_ERROR, 'COPASI binary is not executable or does not exist under "' + copasiExe + '"')
self.errorMsg = 'COPASI binary is not executable or does not exist under "' + copasiExe + '"'
g.log(LOG_ERROR, self.errorMsg)
return False

args = [copasiExe, "--nologo", self.inputFilename]
Expand Down Expand Up @@ -221,9 +232,14 @@ def cleanup(self):
if stats.isValid:
# overwrite the input file with parameter values corresponding to the best result so far
paramsDict = dict(zip(self.job.params, stats.params))
self.copasiFile.createCopy(self.inputFilename, self.reportFilename,
self.job.params, [self.methodName],
paramsDict, self.job.areParametersChangeable)
try:
self.copasiFile.createCopy(self.inputFilename, self.reportFilename,
self.job.params, [self.methodName],
paramsDict, self.job.areParametersChangeable)
except Exception as ex:
self.errorMsg = 'Cannot create the final model file {} with the best results: {}'.format(self.inputFilename, ex)
g.log(LOG_ERROR, self.errorMsg)


def checkReport(self, hasTerminated, now):
assert self.isActive
Expand Down
30 changes: 23 additions & 7 deletions source/strategy.py
Original file line number Diff line number Diff line change
Expand Up @@ -400,13 +400,16 @@ def dumpResults(self, totalLimit = 0):
allParams = self.copasiConfig["params"]

rank = 1
with open(filename, "w") as f:
self.dumpCsvFileHeader(f)
for job in allJobsByBestOfValue:
job.dumpResults(f, rank, allParams)
if totalLimit and rank >= totalLimit:
break
rank += 1
try:
with open(filename, "w") as f:
self.dumpCsvFileHeader(f)
for job in allJobsByBestOfValue:
job.dumpResults(f, rank, allParams)
if totalLimit and rank >= totalLimit:
break
rank += 1
except Exception as ex:
g.log(LOG_ERROR, "cannot save results to {}: {}".format(filename, ex))

g.log(LOG_INFO, '<spacescanner>: results of finished jobs saved in "' + filename + '"')
return filename
Expand Down Expand Up @@ -705,6 +708,15 @@ def finishActivePool(self):
self.dumpResults()


def updateErrorMsg(self, pool):
if pool.errorMsg:
if self.lastError == "":
self.lastError = pool.errorMsg
elif pool.errorMsg != "":
self.lastError += "\n" + pool.errorMsg
pool.errorMsg = ""


def execute(self):
parameterSelections = []

Expand Down Expand Up @@ -773,11 +785,15 @@ def execute(self):
self.activeJobPool = pool

pool.start()
self.updateErrorMsg(pool)

while True:
time.sleep(1.0)
if self.doQuitFlag:
return True

self.updateErrorMsg(pool)

try:
pool.refresh()
except Exception as e:
Expand Down
9 changes: 6 additions & 3 deletions source/webserver.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,11 @@ def saveInFile(self, contents, filename):
except:
pass
filename = os.path.join(dirname, filename)
with open(filename, "wb") as f:
f.write(contents.encode("UTF-8"))
try:
with open(filename, "wb") as f:
f.write(contents.encode("UTF-8"))
except:
g.log(LOG_ERROR, "cannot save to file")
return filename

def sendDefaultHeaders(self, contents, isJSON = True, contentType = None):
Expand Down Expand Up @@ -209,7 +212,7 @@ def do_GET(self):
"resultsPresent" : sm.getNumFinishedJobs() > 0,
"error" : sm.lastError }
# XXX: perhaps resetting this should be timer based?
sm.lastError = None
sm.lastError = ""
elif o.path == '/allstatus':
response = sm.ioGetAllJobs(qs)
elif o.path == '/activestatus':
Expand Down

0 comments on commit 2c2e5d5

Please sign in to comment.