Beispiel #1
0
 def get_ftp_event_detail(ftp_event_id):
     """获取文件事件详情"""
     # 文件事件详情
     result = FtpEventModel.get_ftp_event_detail(db.etl_db, ftp_event_id)
     # 事件中任务流
     result['interface_id'] = FtpEventModel.get_ftp_event_interface(
         db.etl_db, ftp_event_id)
     return Response(result=result)
Beispiel #2
0
 def delete_ftp_event(ftp_event_id):
     """删除调度详情"""
     for item in ftp_event_id:
         try:
             run_id = 'ftp_event_%s' % item
             detail = FtpEventModel.get_ftp_event_detail(db.etl_db, item)
             FtpEventModel.delete_ftp_event_detail(db.etl_db, item)
             FtpEventModel.delete_file_event_interface(db.etl_db, item)
             if detail['status'] != 0:
                 EventHandler.remove_job(run_id)
         except Exception as e:
             log.error('删除调度异常[ERROR: %s]' % e, exc_info=True)
             abort(400, **make_result(status=400, msg='删除调度错误, 该调度不存在'))
     return Response(ftp_event_id=ftp_event_id)
Beispiel #3
0
 def get_ftp_event_list(event_name, status, page, limit):
     """获取文件事件列表"""
     condition = []
     if event_name:
         condition.append('event_name LIKE "%%%%%s%%%%"' % event_name)
     if status == 1:
         condition.append('status = 0')
     elif status == 2:
         condition.append('status = 1')
     elif status == 3:
         condition.append('status = 2')
     condition = 'WHERE ' + ' AND '.join(condition) if condition else ''
     result = FtpEventModel.get_ftp_event_list(db.etl_db, condition, page,
                                               limit)
     total = FtpEventModel.get_ftp_event_list_count(db.etl_db, condition)
     return Response(result=result, total=total)
Beispiel #4
0
 def action_ftp_event(ftp_event_id, action, user_id):
     """暂停/恢复调度事件"""
     for item in ftp_event_id:
         try:
             run_id = 'ftp_event_%s' % item
             # 暂停调度任务
             if action == 1:
                 FtpEventModel.update_ftp_event_status(
                     db.etl_db, item, 2, user_id)
                 EventHandler.pause_job(run_id)
             # 恢复调度任务
             elif action == 2:
                 FtpEventModel.update_ftp_event_status(
                     db.etl_db, item, 1, user_id)
                 EventHandler.resume_job(run_id)
         except Exception as e:
             log.error('暂停/恢复调度异常 [ERROR: %s]' % e, exc_info=True)
             abort(400, **make_result(status=400, msg='暂停/恢复调度任务异常'))
     return Response(ftp_event_id=ftp_event_id)
Beispiel #5
0
 def add_ftp_event_detail(event_name, event_desc, ftp_id, data_path,
                          file_name, interface_id, start_time, end_time,
                          date_time, interval_value, user_id):
     """新增文件事件详情"""
     # 新增事件详情
     ftp_event_id = FtpEventModel.add_ftp_event_detail(
         db.etl_db, event_name, event_desc, ftp_id, data_path, file_name,
         interval_value, start_time, end_time, date_time, user_id)
     # 新增调度
     run_id = 'ftp_event_%s' % ftp_event_id
     minute = '*/%s' % interval_value
     hour = '%d-%d' % (start_time, end_time)
     EventHandler.add_event(run_id, ftp_event_id, minute, hour)
     # 新增任务流依赖
     interface_id = interface_id.split(',')
     insert_data = []
     for item in interface_id:
         insert_data.append({
             'ftp_event_id': ftp_event_id,
             'interface_id': item
         })
     FtpEventModel.add_file_event_interface(db.etl_db, insert_data)
     return Response(ftp_event_id=ftp_event_id)
Beispiel #6
0
 def update_ftp_event_detail(ftp_event_id, event_name, event_desc, ftp_id,
                             data_path, file_name, interface_id, start_time,
                             end_time, date_time, interval_value,
                             old_status, new_status, user_id):
     """修改文件事件详情"""
     # 修改事件详情
     FtpEventModel.update_ftp_event_detail(db.etl_db, ftp_event_id,
                                           event_name, event_desc, ftp_id,
                                           data_path, file_name,
                                           interval_value, start_time,
                                           end_time, date_time, new_status,
                                           user_id)
     # 修改任务流依赖
     interface_id = interface_id.split(',')
     insert_data = []
     for item in interface_id:
         insert_data.append({
             'ftp_event_id': ftp_event_id,
             'interface_id': item
         })
     FtpEventModel.delete_file_event_interface(db.etl_db, ftp_event_id)
     FtpEventModel.add_file_event_interface(db.etl_db, insert_data)
     # 修改文件事件状态
     run_id = 'ftp_event_%s' % ftp_event_id
     minute = '*/%s' % interval_value
     hour = '%d-%d' % (start_time, end_time)
     # 新增调度
     # 仍失效
     if old_status == 0 and new_status == 0:
         pass
     # 新增 or 先新增后暂停
     elif old_status == 0 and new_status == 1 or old_status == 0 and new_status == 2:
         EventHandler.add_event(run_id, ftp_event_id, minute, hour)
     # 修改
     else:
         EventHandler.modify_event(run_id, ftp_event_id, minute, hour)
     # 先新增后暂停
     if old_status == 0 and new_status == 2:
         EventHandler.pause_job(run_id)
     # 暂停
     elif old_status == 1 and new_status == 2:
         EventHandler.pause_job(run_id)
     # 失效
     elif old_status == 1 and new_status == 0 or old_status == 2 and new_status == 0:
         EventHandler.remove_job(run_id)
     # 恢复
     elif old_status == 2 and new_status == 1:
         EventHandler.resume_job(run_id)
     return Response(ftp_event_id=ftp_event_id)
Beispiel #7
0
def get_event_job(event_id, exec_type=1, run_date='', date_format='%Y%m%d'):
    """
    事件执行开始方法
    1.传入事件id(ftp_event_id)
    2.获取事件详情(任务流id, 任务流名称, 数据日期)
    3.获取FTP服务器配置(传入ftp_event_id)
    4.FTP服务器不存在抛出异常
    5.检测FTP服务器连接, 将数据日期替换文件名, 查询文件是否存在
    6.不存在退出
    7.条件一: 文件存在; 条件二: 未存在当前数据日期的成功执行记录(调度id查询), 执行任务流
    8.构造任务流, for任务流列表, return任务流依赖数据结构, 每个dict遍历一遍, 是否存在未for的key,
    如果存在(该任务流在之前任务流的数据结构中), 跳过该任务流, 写入数据库, 执行部分同调度触发, 执行成功时修改数据日期到当天
    :param event_id: 事件id
    :param exec_type: 执行类型: 1.自动, 2.手动
    :param run_date: 手动传入$date日期
    :param date_format: $date日期格式
    :return: None
    """
    # 传入日期
    if run_date and date_format:
        run_time = time.strftime(date_format, time.strptime(run_date, '%Y-%m-%d'))
    else:
        event_detail = FtpEventModel.get_ftp_event_detail(db.etl_db, event_id)
        if event_detail and event_detail['date_time']:
            run_time = time.strftime(date_format, time.strptime(event_detail['date_time'], '%Y-%m-%d'))
        else:
            run_time = time.strftime(date_format, time.localtime())
    # 任务流详情
    detail_list = EventModel.get_interface_detail_by_ftp_event_id(db.etl_db, event_id)
    # 检测是否执行
    # 获取FTP服务器配置
    ftp_detail = FtpEventModel.get_ftp_detail_by_event_id(db.etl_db, event_id)
    # 检测FTP服务器文件是否存在
    if isinstance(ftp_detail['ftp_passwd'], bytes):
        ftp_detail['ftp_passwd'] = ftp_detail['ftp_passwd'].decode('utf-8', 'ignore')
    try:
        # FTP连接
        if ftp_detail['ftp_type'] == 1:
            ftp = FtpLink(ftp_detail['ftp_host'], ftp_detail['ftp_port'], ftp_detail['ftp_user'], ftp_detail['ftp_passwd'])
            FtpModel.update_ftp_status(db.etl_db, ftp_detail['ftp_id'], 0)
            # 文件名
            file_name = time.strftime(ftp_detail['file_name'], time.strptime(ftp_detail['date_time'], '%Y-%m-%d'))
            result = ftp.test_file(ftp_detail['data_path'], file_name)
            ftp.close()
        # SFTP连接
        elif ftp_detail['ftp_type'] == 2:
            ftp = SftpLink(ftp_detail['ftp_host'], ftp_detail['ftp_port'], ftp_detail['ftp_user'], ftp_detail['ftp_passwd'])
            FtpModel.update_ftp_status(db.etl_db, ftp_detail['ftp_id'], 0)
            # 文件名
            file_name = time.strftime(ftp_detail['file_name'], time.strptime(ftp_detail['date_time'], '%Y-%m-%d'))
            result = ftp.test_file(ftp_detail['data_path'], file_name)
            ftp.close()
        else:
            FtpModel.update_ftp_status(db.etl_db, ftp_detail['ftp_id'], 1)
            return Response(status=400, msg='FTP服务器类型未知')
    except:
        FtpModel.update_ftp_status(db.etl_db, ftp_detail['ftp_id'], 1)
        return Response(status=400, msg='FTP连接异常')
    # 当前数据日期的成功执行记录
    success_detail = EventModel.get_event_exec_detail_success(db.etl_db, event_id, ftp_detail['date_time'])
    # 文件存在, 未存在当前数据日期的成功执行记录(调度id查询)
    if result and not success_detail:
        # 执行任务流
        pass
    else:
        return Response(status=400, msg='FTP文件目录不存在')
    interface_dag_nodes = {}
    # 遍历多个任务流
    for detail in detail_list:
        # 生成执行任务流前后依赖关系
        dag = generate_interface_dag_by_event(detail)
        # 生成执行任务流树形关系
        tree = generate_interface_tree_by_event(detail)
        tree_nodes = [_ for _ in tree.keys()]
        # 填充树形节点
        for key in set(tree_nodes):
            dag[key]['is_tree'] = 1
        # 合并
        interface_dag_nodes.update(dag)

    if not interface_dag_nodes:
        return
    # 需执行任务流
    interface_tree_nodes = {key: value for key, value in interface_dag_nodes.items() if value.get('is_tree', 0) == 1}
    # 获取所有任务流的任务详情
    job_nodes = {}
    for _, item in interface_tree_nodes.items():
        jobs = generate_job_dag_by_interface(item['id'])
        job_nodes[item['id']] = jobs
    # 添加执行主表, 任务流表, 任务表至数据库
    exec_id = add_event_exec_record(event_id, interface_dag_nodes, job_nodes, exec_type, run_time, date_format)
    # 初始任务流
    start_interface = [_ for _, item in interface_tree_nodes.items() if item['level'] == 0]
    # 开始执行初始任务流中的任务
    flag = False
    for curr_interface in start_interface:
        start_jobs = job_nodes[curr_interface]
        # 任务流中任务为空, 则视调度已完成
        if not start_jobs:
            flag = True
            log.info('事件任务流中任务为空: 事件id: %s, 执行id: %s, 任务流id: %s' % (event_id, exec_id, curr_interface))
            # 修改执行任务流[成功]
            with MysqlLock(config.mysql.etl, 'event_lock_%s' % exec_id):
                EventModel.update_event_exec_interface_status(db.etl_db, exec_id, curr_interface, 0)
        else:
            # 修改执行任务流[运行中]
            with MysqlLock(config.mysql.etl, 'event_lock_%s' % exec_id):
                EventModel.update_event_exec_interface_status(db.etl_db, exec_id, curr_interface, 1)
            # rpc分发任务
            for job in start_jobs:
                if job['level'] == 0:
                    # 修改执行详情表状态[运行中]
                    with MysqlLock(config.mysql.etl, 'event_lock_%s' % exec_id):
                        EventModel.update_event_exec_job_status(db.etl_db, exec_id, curr_interface, job['id'],
                                                                'running')
                    log.info('事件分发任务: 执行id: %s, 任务流id: %s, 任务id: %s' % (exec_id, curr_interface, job['id']))
                    rpc_push_job(exec_id, curr_interface, job['id'], job['server_host'], config.exec.port,
                                 ','.join(job['params_value']), job['server_dir'], job['server_script'],
                                 job['return_code'], job['status'], run_date=run_time)
    # 继续下一个任务流
    if flag:
        next_jobs = continue_event_execute_interface(exec_id, exec_type=exec_type, run_date=run_time)
        if not next_jobs:
            return
        for interface_id, item in next_jobs.items():
            for job_id in set(item['job_id']):
                log.info('分发任务: 执行id: %s, 任务流id: %s, 任务id: %s' % (exec_id, interface_id, job_id))
                nodes = item['nodes']
                rpc_push_job(exec_id, interface_id, job_id, nodes[job_id]['server_host'],
                             config.exec.port, nodes[job_id]['params_value'],
                             nodes[job_id]['server_dir'], nodes[job_id]['server_script'],
                             nodes[job_id]['return_code'], nodes[job_id]['status'], run_date=run_time)