Beispiel #1
0
    def __init__(self):
        # assert hasattr(g, 'user_id'), '找不到用户信息'
        # assert hasattr(g, 'tanent_id'), '找不到用户企业信息'
        self.user_id = g.user_id if hasattr(g, 'user_id') else 0
        self.tenant_id = g.tenant_id if hasattr(g, 'tenant_id') else 0

        self.task_dao = TaskDAO()
Beispiel #2
0
    def start_thread_save_db(self, msg_list):
        taskdao = TaskDAO()

        # 多线程将缓存保存到数据库
        def start_thread(x):
            batch = Utils.get_batch(x)
            thread_key = taskdao.thread_key.format(batch)
            if not self.aios_redis.get(thread_key):
                threading.Thread(target=taskdao.save_to_db,
                                 args=(g.user_id, g.tenant_id, batch),
                                 daemon=True).start()
                self.aios_print('启动定时调度线程', batch)
                self.aios_redis.set(thread_key, 'Running',
                                    taskdao.THREAD_KEY_TIMEOUT)
            if self.aios_redis.ttl(thread_key) < 10:
                threading.Thread(target=taskdao.save_to_db,
                                 args=(g.user_id, g.tenant_id, batch),
                                 daemon=True).start()
                self.aios_print('线程已存在,失效时间快到了,重新启动定时调度线程', batch)
                self.aios_redis.set(thread_key, 'Running',
                                    taskdao.THREAD_KEY_TIMEOUT)
            else:
                self.aios_print('线程已存在,不需要开启', batch)

        # 启动多个线程
        _.chain(msg_list). \
            map_(lambda x: Utils.get_host(x.get('dir_path'))). \
            uniq(). \
            for_each(start_thread). \
            value()
Beispiel #3
0
class TaskBLL():
    def __init__(self):
        # assert hasattr(g, 'user_id'), '找不到用户信息'
        # assert hasattr(g, 'tanent_id'), '找不到用户企业信息'
        self.user_id = g.user_id if hasattr(g, 'user_id') else 0
        self.tenant_id = g.tenant_id if hasattr(g, 'tenant_id') else 0

        self.task_dao = TaskDAO()

    def get_task_from_cache(self, task_id):
        return self.task_dao.get_task_from_cache(self.tenant_id, task_id)
Beispiel #4
0
    def single_file_handler(self, single_chunk_files):
        '''单分片文件处理方法
        '''
        succ_list = []
        err_list = []
        wait_add_tasks = []
        wait_update_tasks = []
        taskdao = TaskDAO()

        tenant_id = g.tenant_id if hasattr(g, 'tenant_id') else 0
        batches = _.uniq(
            [Utils.get_batch(i.get('dir_path')) for i in single_chunk_files])
        task_ids = [i.get('file_key') for i in single_chunk_files]
        exist_tasks = taskdao.get_tasks(tenant_id, batches, task_ids)
        exist_tasks_map = {}
        for exist_task in exist_tasks:
            exist_tasks_map[exist_task.task_id] = exist_task.id

        for single_chunk_file in single_chunk_files:
            try:
                file_key = single_chunk_file.get('file_key')
                dir_path = single_chunk_file.get('dir_path')
                file_name = single_chunk_file.get('file_name')
                tenant_id = single_chunk_file.get('tenant_id')
                user_id = single_chunk_file.get('user_id')

                merged_file = os.path.join(dir_path, file_name)
                final_merged_file = os.path.join(dir_path, f'{file_key}.1')
                shutil.move(final_merged_file, merged_file)

                task_json = {
                    'created_by': user_id,
                    'tenant_id': tenant_id,
                    'task_id': file_key,
                    'chunks': '1',
                    'status': TASK_STATUS_MERGED,
                    'size': os.path.getsize(merged_file),
                    'link': {
                        'host': Utils.get_host(dir_path)
                    },
                    'batch': Utils.get_batch(dir_path)
                }
                if exist_tasks_map.get(file_key):
                    task_json['id'] = exist_tasks_map.get(file_key)
                    wait_update_tasks.append(task_json)
                else:
                    wait_add_tasks.append(task_json)
                succ_list.append({'file_key': file_key, 'curr_chunk': 1})
            except Exception as err:
                err_list.append({'file_key': file_key, 'curr_chunk': 1})

        if len(wait_add_tasks):
            taskdao.bulk_add(wait_add_tasks)
        if len(wait_update_tasks):
            taskdao.bulk_update(wait_update_tasks)
        return succ_list, err_list
Beispiel #5
0
    def notify_thread_stop(self, msg_list):
        taskdao = TaskDAO()

        def stop_thread(x):
            batch = Utils.get_batch(x)
            thread_key = taskdao.thread_key.format(batch)
            self.aios_redis.set(thread_key, 'Stop')

        _.chain(msg_list). \
            map_(lambda x: Utils.get_host(x.get('dir_path'))). \
            uniq(). \
            for_each(stop_thread). \
            value()
Beispiel #6
0
 def get_task(self, tenant_id, task_id):
     return TaskDAO().get_task(tenant_id, task_id)
Beispiel #7
0
    def multi_file_handler(self, msg):
        '''子进程处理单个文件的写入
        '''
        try:
            # 上传进程内部加载sqlalchemy时需要控制每个进程的数据库连接池大小
            os.environ['SQLALCHEMY_POOL_SIZE'] = '1'
            from run import app as inner_app
            from app import aios_redis

            with inner_app.app_context():
                self.aios_redis = aios_redis

                file_key = msg.get('file_key')
                dir_path = msg.get('dir_path')
                file_name = msg.get('file_name')
                curr_chunk = msg.get('curr_chunk')
                total_chunks = msg.get('total_chunks')
                tenant_id = msg.get('tenant_id')
                user_id = msg.get('user_id')
                cache_expired_time = msg.get('cache_expired_time')

                wait_lock = f'plus_uploader:lock:{file_key}'
                while not self.aios_redis.setnx(wait_lock,
                                                f'lock.{curr_chunk}'):
                    # self.aios_print(file_key, curr_chunk, 'task waiting...')
                    time.sleep(0.001)
                else:
                    self.lock = f'{wait_lock} by {curr_chunk}'
                    self.aios_print(file_key, curr_chunk,
                                    f'current lock: lock.{curr_chunk}')
                    # 锁独占状态
                    # wait_lock超时时间 = 已存在但未合并的分片个数 * 单个分片预估的失效时间
                    parts = len(
                        _.filter_(
                            os.listdir(dir_path),
                            lambda x: '-' not in x and '.deleted' not in x))
                    count = max(parts, 1)
                    self.aios_print(f'文件存放目录{dir_path}, 实时已存在的分片数: {parts}')
                    self.aios_redis.expire(wait_lock,
                                           cache_expired_time * count)
                    # self.aios_print(f'修正的lock超时时间, {cache_expired_time * count}')
                    # 更新任务状态
                    args = {
                        'task_id': file_key,
                        'tenant_id': tenant_id,
                        'created_by': user_id,
                        'updated_by': user_id,
                        'batch': Utils.get_batch(dir_path),
                        'status': TASK_STATUS_NONE,
                        'chunks': '',
                        'size': 0,
                        'link': {
                            'host': Utils.get_host(dir_path)
                        }
                    }
                    taskdao = TaskDAO()
                    # task_json = taskdao.get_task_from_cache(tenant_id, file_key)
                    task_json = taskdao.get_task(tenant_id,
                                                 file_key,
                                                 json=True)
                    if task_json is None:
                        task_json = taskdao.add(args)

                    if task_json['status'] != TASK_STATUS_MERGED:
                        task_json['status'] = TASK_STATUS_MERGING
                        # taskdao.update(task_json)
                        TaskModel.bulk_update_mappings([task_json])

                        # 合并分片
                        # 合并后的完整文件路径
                        merged_file = os.path.join(dir_path, file_name)

                        merge_process = self.partation_merge(
                            dir_path, file_key, total_chunks)
                        merge_process = _.map_(
                            merge_process,
                            lambda x: x.replace(f'{file_key}.', ''))
                        except_complete_name = f'1-{total_chunks}' if total_chunks > 1 else '1'
                        # 检测是否完整 ['1-701'] except_complete_name 1-701
                        self.aios_print('检测是否完整', merge_process,
                                        'except_complete_name',
                                        except_complete_name)
                        if except_complete_name in merge_process:
                            for f in os.listdir(dir_path):
                                self.aios_print('比较文件名', f,
                                                except_complete_name)
                                if f.startswith(f'{file_key}.') and (
                                        not f.endswith(except_complete_name)):
                                    Utils.try_remove(os.path.join(dir_path, f))
                                    self.aios_print('删除残留异常文件', f)
                            # 修改合并后的文件名称
                            final_merged_file = os.path.join(
                                dir_path, f'{file_key}.{except_complete_name}')
                            shutil.move(final_merged_file, merged_file)
                            self.aios_print('文件改名', final_merged_file, '>>',
                                            merged_file)
                            # 记录任务状态
                            task_json['chunks'] = ','.join(
                                [str(i + 1) for i in range(total_chunks)])
                            task_json['status'] = TASK_STATUS_MERGED
                            task_json['size'] = os.path.getsize(merged_file)

                            task_json['link'] = {
                                'host': Utils.get_host(dir_path)
                            }

                            # 合并完成
                            self.aios_print(f'{curr_chunk}.合并完成')
                        else:
                            # ['1', '3-5', '10']
                            covert_process = []
                            for section in merge_process:
                                if '-' in section:
                                    [left, right] = section.split('-')
                                    covert_process.extend([
                                        str(i)
                                        for i in range(int(left),
                                                       int(right) + 1)
                                    ])
                                else:
                                    covert_process.append(section)

                            task_json['chunks'] = ','.join(covert_process)
                            # 不完整
                            self.aios_print(f'{curr_chunk}.不完整,继续等待')
                        # 保存到缓存
                        # taskdao.update(task_json)
                        self.aios_print(f'更新状态, {task_json}')
                        TaskModel.bulk_update_mappings([task_json])
                    else:
                        # 已经合并完成后,不需要再次合并,直接退出
                        self.aios_print(f'{curr_chunk}.已经合并完成后, 不需要再次合并')
                    # 释放锁
                    self.aios_redis.delete(wait_lock)
                    self.aios_print(f'结束.{curr_chunk}/{total_chunks}')

                    # 清理被标记的可删除分片
                    for file in os.listdir(dir_path):
                        if file.endswith('.deleted'):
                            self.aios_print('清理被标记的可删除分片', file)
                            Utils.try_remove(os.path.join(dir_path, file))

                return {'file_key': file_key, 'curr_chunk': curr_chunk}, None
        except Exception as err:
            import traceback
            traceback.print_exc()
            print('multi_file_handler', err)
            return None, {
                'file_key': msg['file_key'],
                'curr_chunk': msg['curr_chunk']
            }