def show_task_log(): "Show log of tasks run." run_db = ox_run_db.create() start_utc = request.args.get('start_utc', None) end_utc = request.args.get('end_utc', None) limit = int(request.args.get('limit', 100)) tasks = run_db.get_tasks(start_utc=start_utc, end_utc=end_utc) tasks = run_db.limit_task_count(tasks, limit) other = [] task_dict = collections.OrderedDict([('started', []), ('finished', [])]) for item in reversed( sorted(tasks, key=lambda t: (t.task_end_utc, t.task_start_utc))): if item.task_status in task_dict: task_dict[item.task_status].append(item) else: other.append(item) task_dict['other'] = other return render_template('task_log.html', title='Task log', start_utc=start_utc, end_utc=end_utc, task_dict=task_dict, limit=limit)
def check_jobs(): """Check if various jobs have been running. The following URL parameters can be provided: - names: - Comma separated list of names of tasks to check. - seconds (default 3600) - How many seconds are allowed since last completion of a job named in the names parameter. If a job in names has not finished within the given seconds, then we complain. """ my_db = ox_run_db.create() late_jobs = [] try: # Use try block so return 500 if see an exception if not _check_health_token(): abort(403) seconds = int(request.args.get('seconds', '3600')) name_list = request.args.get('names').split(',') my_now = datetime.datetime.utcnow() for name in name_list: logging.info('Checking task "%s"', name) latest = my_db.get_latest(name) if not latest: late_jobs.append((name, 'not found', 'N/A')) else: task_end_utc = datetime.datetime.strptime( str(latest.task_end_utc), '%Y-%m-%d %H:%M:%S.%f') gap = (my_now - task_end_utc).total_seconds() if gap > seconds: late_jobs.append((name, task_end_utc, gap)) if late_jobs: msg = '\n'.join(['Found late jobs:'] + [ '%s: finished at %s which is %s > %s seconds late' % (name, task_end_utc, gap, seconds) for (name, task_end_utc, gap) in late_jobs ]) logging.error(msg) return json.dumps({ 'result': 'error', 'error': msg }), 412, { 'ContentType': 'application/json' } except Exception as problem: # pylint: disable=broad-except logging.error('Problem in health_check: %s', str(problem)) abort(500) return json.dumps({'result': 'success'}), 200, { 'ContentType': 'application/json' }
def list_tasks(): "Show list of tasks so you can inspect them." my_db = ox_run_db.create() limit = int(request.args.get('limit', 100)) start_utc = request.args.get('start_utc', None) end_utc = request.args.get('end_utc', None) tasks = my_db.get_tasks(start_utc=start_utc, end_utc=end_utc) total = len(tasks) tasks = my_db.limit_task_count(tasks, limit) return render_template('task_list.html', title='Task List', tasks=tasks, total=total, limit=limit)
def delete_task_from_db(): """Delete a task from the task database. This is mainly intended to be used from the task list and not so useful directly since it requires the task_id. """ task_id = request.args.get('task_id', None) if task_id: run_db = ox_run_db.create() run_db.delete_task(task_id) return render_template( 'generic_display.html', commentary=('Delete task with id %s from database.' % task_id)) return render_template( 'generic_display.html', commentary=('Found no task_id so cannot do anything.'))
def run_ox_task(cls, ox_herd_task): """Entry point to run the task. This is what python rq or other managers will use to start the task. """ job_name = ox_herd_task.name run_db = ox_herd_task.run_db rdb = ox_run_db.create(run_db) cls.pre_call(ox_herd_task, rdb) try: result = cls.main_call(ox_herd_task) except Exception as problem: logging.error('For job %s; storing exception result: %s', job_name, str(problem)) cls.post_call(ox_herd_task, rdb, str(problem), 'exception') raise cls.post_call(ox_herd_task, rdb, result) return result
def show_task(): "Show information about a task." task_id = request.args.get('task_id', None) run_db = ox_run_db.create() try: task_data = run_db.get_task(task_id) if not task_data: raise KeyError('No task with id %s' % str(task_id)) except Exception as problem: # pylint: disable=broad-except return render_template( 'generic_error.html', title='Could not find task', commentary='Could not find task with id %s because %s' % (task_id, problem)) template = request.args.get('template', task_data.template) template = template if (template and template.strip() and template != 'default') else ( 'generic_ox_task_result.html') return render_template(template, title='Task Report', task_data=task_data)
def record_finished_job(): """REST API endpoint to record that a job finished. You can send a request with the following: - task_id: - The id returned by record_started_job if you have called that. If you have not called record_started_job and want to record both start and finish in one go then omit this and provide task_name instead (see below). - task_name: - If you have not already called record_started_job and just want to record the start and finish of the job, then provide a string name in task_name and omit task_id. - return_value: - Return value of running the task. """ if current_user is None and not _check_health_token(): abort(403) my_db = ox_run_db.create() try: record = json.loads(request.data) task_id = record.get('task_id', None) if task_id is None: task_id = my_db.record_task_start(record['task_name']) record.pop('task_name') record['task_id'] = task_id my_db.record_task_finish(**record) except KeyError as problem: return json.dumps({ 'result': 'error', 'error': 'Could not find required value for "%s"' % str(problem) }), 400, { 'ContentType': 'application/json' } return json.dumps({'result': 'success'}), 200, { 'ContentType': 'application/json' }
def get_latest(task_name): """Get info on latest finished version of task named <task_name> If successful, you can do something like the folllowing to get the completion time of the latest task: datetime.datetime.strptime(my_request.json()['task_end_utc'], '%Y-%m-%d %H:%M:%S.%f') """ task_result = ox_run_db.create().get_latest(task_name) if task_result is None: result = {} else: result = { n: getattr(task_result, n, None) for n in [ 'task_id', 'task_name', 'task_start_utc', 'task_end_utc', 'return_value', 'json_data', 'pickle_data' ] } return json.dumps(result), 200, {'ContentType': 'application/json'}