Skip to content

Commit eee7188

Browse files
jecarrKadeMorton
authored andcommitted
Updated report-error process
- Distinguished error-types during URL-checking - Refactored some app-method calls - Added an on-error call to handle unexpected errors during report-URL-processing
1 parent 8bf3fd8 commit eee7188

File tree

2 files changed

+72
-31
lines changed

2 files changed

+72
-31
lines changed

threadcomponents/service/rest_svc.py

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -254,9 +254,11 @@ async def _insert_batch_reports(self, request, batch, row_count, token=None):
254254
if "#" in url:
255255
url = url[: url.index("#")]
256256
await self.web_svc.verify_url(request, url=url)
257+
257258
# Raised if verify_url() fails
258-
except ValueError as ve:
259-
return dict(error=str(ve), alert_user=1)
259+
except (SystemError, ValueError) as ve:
260+
error_prefix = "URL checks failed:" if isinstance(ve, ValueError) else "System-error:"
261+
return dict(error=f"{error_prefix} {ve}", alert_user=1)
260262

261263
# Ensure the report has a unique title
262264
title = await self.data_svc.get_unique_title(title)
@@ -372,22 +374,27 @@ async def check_queue(self):
372374
"""
373375
logging.info("CHECKING QUEUE")
374376
self.clean_current_tasks()
377+
375378
while self.queue.qsize() > 0: # while there are still tasks to do...
376379
logging.info("QUEUE SIZE: " + str(self.queue.qsize()))
377380
await asyncio.sleep(1) # allow other tasks to run while waiting
381+
378382
while len(self.current_tasks) >= self.MAX_TASKS: # check resource pool until a task is finished
379383
self.clean_current_tasks()
380384
await asyncio.sleep(1) # allow other tasks to run while waiting
385+
381386
criteria = await self.queue.get() # get next task off queue and run it
382387
# Use run_in_executor (due to event loop potentially blocked otherwise) to start analysis
383388
loop = asyncio.get_running_loop()
389+
384390
try:
385391
task = loop.run_in_executor(None, partial(self.run_start_analysis, criteria=criteria))
386392
self.current_tasks.append(task)
387393
await task
394+
388395
except Exception as e:
389396
logging.error("Report analysis failed: " + str(e))
390-
await self.error_report(criteria)
397+
await self.error_report(criteria, high_severity=True)
391398
continue
392399

393400
def run_start_analysis(self, criteria=None):
@@ -401,13 +408,16 @@ def run_start_analysis(self, criteria=None):
401408
finally:
402409
loop.close()
403410

404-
async def error_report(self, report):
411+
async def error_report(self, report, high_severity=False):
405412
"""Function to error a given report."""
406413
report_id = report[UID]
407414
await self.dao.update("reports", where=dict(uid=report_id), data=dict(error=self.dao.db_true_val))
408415
self.remove_report_from_queue_map(report)
409416
await self.remove_report_if_automatically_generated(report_id)
410417

418+
if high_severity:
419+
await self.web_svc.on_report_error(None)
420+
411421
async def start_analysis(self, criteria=None):
412422
report_id = criteria[UID]
413423
logging.info("Beginning analysis for " + report_id)

threadcomponents/service/web_svc.py

Lines changed: 58 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -113,63 +113,94 @@ def check_and_clear_cached_responses(self):
113113
if len(self.cached_responses) > 100:
114114
self.cached_responses = dict()
115115

116+
async def _call_app_method(
117+
self,
118+
request,
119+
*args,
120+
method_name=None,
121+
return_val_when_local=None,
122+
return_val_on_error=None,
123+
**kwargs,
124+
):
125+
"""Function to call an app-method given its name."""
126+
if self.is_local:
127+
# Not applicable to local setups
128+
return return_val_when_local
129+
130+
try:
131+
# Attempt to use app's method; log if this couldn't be done
132+
app_method = getattr(request.app if request else self.app, method_name)
133+
return await app_method(*args, **kwargs)
134+
135+
except Exception as e:
136+
logging.error(f"Misconfigured app: {method_name}() error: {e}")
137+
return return_val_on_error
138+
116139
async def action_allowed(self, request, action, context=None):
117140
"""Function to check an action is permitted given a request."""
118141
if self.is_local:
119142
# A permission-checker is not implemented for local-use
120143
# and the user is in control of all their data, so allow the action
121144
return True
145+
122146
try:
123147
# Attempt to use app's method to check permission; log if this couldn't be done
124148
return await request.app.permission_checker(request, action, context)
149+
125150
except (TypeError, AttributeError) as e:
126-
logging.error("Misconfigured app: permission_checker() error: " + str(e))
151+
logging.error(f"Misconfigured app: permission_checker() error: {e}")
127152
raise web.HTTPInternalServerError()
128153

129154
async def url_allowed(self, request, url):
130155
"""Function to check a URL is allowed to be submitted."""
131156
if self.is_local:
132157
# A URL-checker is not implemented for local-use so allow the action
133158
return True
159+
134160
try:
135161
# Attempt to use app's method to check URL; log if this couldn't be done
136162
return await request.app.url_checker(request, url)
163+
137164
except (TypeError, AttributeError) as e:
138-
logging.error("Misconfigured app: url_checker() error: " + str(e))
139-
# SystemError makes more sense but we are listening for ValueErrors
140-
raise ValueError("Apologies, this URL could not be processed at this time, please contact us.")
165+
logging.error(f"Misconfigured app: url_checker() error: {e}")
166+
raise SystemError("Apologies, this URL could not be processed at this time, please contact us.")
141167

142168
async def on_report_complete(self, request, report_data):
143169
"""Function to complete any post-complete actions for a report."""
144-
if self.is_local:
145-
# No post-complete actions needed for local-use
146-
return
147-
try:
148-
# Attempt to use app's on-complete method; log if this couldn't be done
149-
return await request.app.on_report_complete(request, report_data)
150-
except (TypeError, AttributeError) as e:
151-
logging.error("Misconfigured app: on_report_complete() error: " + str(e))
170+
return await self._call_app_method(
171+
request,
172+
request,
173+
report_data,
174+
method_name="on_report_complete",
175+
)
176+
177+
async def on_report_error(self, request):
178+
"""Function to complete any submission-error actions for a report."""
179+
return await self._call_app_method(
180+
request,
181+
method_name="on_report_submission_error",
182+
)
152183

153184
async def get_current_arachne_user(self, request):
154185
"""Function to obtain the current Arachne username and token given a request."""
155-
if self.is_local:
156-
return None, None
157-
try:
158-
# Attempt to use app's method to obtain the username & token; log if this couldn't be done
159-
return await request.app.get_current_arachne_user(request)
160-
except (TypeError, AttributeError) as e:
161-
logging.error("Misconfigured app: get_current_arachne_user() error: " + str(e))
162-
return None, None
186+
return await self._call_app_method(
187+
request,
188+
request,
189+
method_name="get_current_arachne_user",
190+
return_val_when_local=(None, None),
191+
return_val_on_error=(None, None),
192+
)
163193

164194
async def auto_gen_data_is_valid(self, request, request_data) -> bool:
165195
"""Function to confirm data for an automatically-generated report is valid."""
166-
if self.is_local:
167-
return True
168-
try:
169-
return await request.app.auto_gen_data_is_valid(request, request_data)
170-
except Exception as e:
171-
logging.error("Misconfigured app: auto_gen_data_is_valid() error: " + str(e))
172-
return False
196+
return await self._call_app_method(
197+
request,
198+
request,
199+
request_data,
200+
method_name="auto_gen_data_is_valid",
201+
return_val_when_local=True,
202+
return_val_on_error=False,
203+
)
173204

174205
async def map_all_html(self, url_input, sentence_limit=None):
175206
a = newspaper.Article(url_input, keep_article_html=True)

0 commit comments

Comments
 (0)