浏览代码

异常处理问题

rambo 1 月之前
父节点
当前提交
08e78d968d

+ 26 - 12
python/api.py

@@ -32,7 +32,7 @@ from service.online_request.module_online_data import AIGCDataRequest
 import asyncio
 from fastapi import BackgroundTasks
 import functools
-import traceback
+import traceback,stat
 import concurrent.futures
 
 def log_exception_with_context(context_message=""):
@@ -374,7 +374,7 @@ async def _process_non_excel_mode(params, goods_art_no_arrays):
         session = SqlQuery()
         pr = CRUD(PhotoRecord)
         images = pr.read_all(session, conditions={"goods_art_no": goods_art_no})
-        
+        session.close()
         if not images:
             raise UnicornException(
                 f"商品货号【{goods_art_no}】未查询到拍摄记录,请检查货号是否正确"
@@ -397,13 +397,13 @@ async def _process_excel_mode(goods_art_no_arrays,excel_df):
     check_path(limit_path)
     
     move_folder_array = check_move_goods_art_no_folder("output", goods_art_no_arrays, limit_path)
+    session = SqlQuery()
     for index, row in excel_df.iterrows():
             goods_art_no_image_dir = str(row["文件夹名称"])
             goods_art_no = str(row["商品货号"])
             print("货号数据", goods_art_no)
             if not goods_art_no:
                 raise UnicornException("货号不能为空")
-            session = SqlQuery()
             pr = CRUD(PhotoRecord)
             images = pr.read_all(session, conditions={"goods_art_no": goods_art_no})
             if not images:
@@ -413,6 +413,7 @@ async def _process_excel_mode(goods_art_no_arrays,excel_df):
             # 货号目录不存在再去进行移动和创建操作
             if move_folder_array.get(goods_art_no) is None:
                 await _process_image_copy_and_move(goods_art_no_image_dir, images,True)
+    session.close()
     return move_folder_array
 
 async def _process_image_copy_and_move(goods_art_no, images,is_excel):
@@ -438,7 +439,10 @@ async def _process_image_copy_and_move(goods_art_no, images,is_excel):
     if not resFlag:
         raise UnicornException(path)
     if is_excel:
-        shutil.rmtree(image_dir)
+        try:
+            shutil.rmtree(image_dir,onerror=settings.handle_remove_readonly)
+        except Exception as e:
+            logger.info(f"删除图片失败:{str(e)}")
 
 async def _build_config_data(params, goods_art_no_arrays):
     """构建配置数据"""
@@ -908,7 +912,6 @@ def get_device_tabs(type: int):
         .order_by(asc("id"))
     )
     result = session.exec(statement).all()
-    session.close()
     sys = CRUD(SysConfigs)
     action_configs = sys.read(session, conditions={"key": "action_configs"})
     session.close()
@@ -946,6 +949,7 @@ def get_device_configs(params: ModelGetDeviceConfig):
         order_by="action_index",
         ascending=True,
     )
+    session.close()
     return {
         "code": 0,
         "msg": "",
@@ -959,6 +963,7 @@ def device_config_detail(params: ModelGetDeviceConfigDetail):
     session = SqlQuery()
     configModel = CRUD(DeviceConfig)
     model = configModel.read(session, conditions={"id": action_id})
+    session.close()
     if model == None:
         return {"code": 1, "msg": "数据不存在", "data": None}
     return {"code": 0, "msg": "", "data": model}
@@ -979,6 +984,7 @@ def device_config_detail_query():
     )
     if model == None:
         model = configModel.read(session, conditions={"tab_id": left_config})
+    session.close()
     return {"code": 0, "msg": "", "data": model}
 
 
@@ -996,6 +1002,7 @@ def get_device_configs(params: ModelGetDeviceConfigDetail):
     if len(configArray) == 1:
         return {"code": 1, "msg": "请至少保留一个配置", "data": None}
     configModel.delete(session, obj_id=action_id)
+    session.close()
     return {"code": 0, "msg": "删除成功", "data": None}
 
 
@@ -1015,6 +1022,7 @@ def save_device_config(params: SaveDeviceConfig):
         # 走编辑逻辑
         kwargs = params.__dict__
         save_device_config = deviceConfig.update(session, obj_id=action_id, **kwargs)
+    session.close()
     return {"code": 0, "msg": "操作成功", "data": save_device_config}
 
 
@@ -1036,7 +1044,7 @@ def reset_config(params: ModelGetDeviceConfig):
         device_config = DeviceConfig(**data)
         session.add(device_config)
     session.commit()
-    # session.close()
+    session.close()
     return {"code": 0, "msg": "操作成功", "data": None}
 
 
@@ -1076,7 +1084,7 @@ def get_photo_records(page: int = 1, size: int = 5):
                 "items": list_item,
             }
         )
-    # session.close()
+    session.close()
     print("循环查询 完成 ", datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
     return {
         "code": 0,
@@ -1094,7 +1102,7 @@ def get_last_photo_record():
         .order_by(desc("photo_create_time"))
     )
     result = session.exec(statement).first()
-    # session.close()
+    session.close()
     return {
         "code": 0,
         "msg": "",
@@ -1109,7 +1117,7 @@ def get_photo_record_detail(goods_art_no: str = None):
     session = SqlQuery()
     photos = CRUD(PhotoRecord)
     items = photos.read_all(session, conditions={"goods_art_no": goods_art_no})
-    # session.close()
+    session.close()
     return {
         "code": 0,
         "msg": "",
@@ -1123,7 +1131,7 @@ def delect_goods_arts(params: PhotoRecordDelete):
     photos = CRUD(PhotoRecord)
     for item in params.goods_art_nos:
         photos.deleteConditions(session, conditions={"goods_art_no": item})
-    # session.close()
+    session.close()
     return {
         "code": 0,
         "msg": "操作成功",
@@ -1171,6 +1179,7 @@ def get_sys_config(key: str = None):
             session.add(config)
             session.commit()  # 合并事务提交
             search_data = json.loads(sys_config_json.get("value"))
+    session.close()
     return {
         "code": 0,
         "msg": "",
@@ -1193,6 +1202,7 @@ def update_left_right_config(params: LeftRightParams):
     save_device_config = sysConfig.updateConditions(
         session, conditions={"key": "action_configs"}, **kwargs
     )
+    session.close()
     return {"code": 0, "msg": "操作成功", "data": None}
 
 
@@ -1205,6 +1215,7 @@ def update_record(params: RecordUpdate):
         return {"code": 1, "msg": "记录不存在", "data": None}
     kwargs = params.__dict__
     save_device_config = photoRecord.update(session, obj_id=params.id, **kwargs)
+    session.close()
     return {"code": 0, "msg": "操作成功", "data": save_device_config}
 
 
@@ -1220,6 +1231,7 @@ def save_sys_configs(params: SysConfigParams):
     save_device_config = sysConfig.updateConditions(
         session, conditions={"key": params.key}, **kwargs
     )
+    session.close()
     return {"code": 0, "msg": "操作成功", "data": save_device_config}
 
 
@@ -1237,7 +1249,6 @@ def insertEmptyLogoList(session):
     config = SysConfigs(**data)
     session.add(config)
     session.commit()
-    session.close()
     item = SysConfigs()
     item.key = "logo_configs"
     item.value = "[]"
@@ -1267,6 +1278,7 @@ def add_logo(params: LogoParams):
         return {"code": 1, "msg": "logo文件不存在", "data": None}
     logo_dir = "{}/data/logo/".format(os.getcwd()).replace("\\", "/")
     check_path(logo_dir)
+    session.close()
     fpath, fname = os.path.split(logo_path)
     logo_path_info = logo_dir + fname
     shutil.copy(logo_path, logo_path_info)  # 复制文件
@@ -1337,7 +1349,7 @@ def syncUserJsonConfigs(token):
                 }
             )
         batch_insert_sys_configs(session, configList)
-
+    session.close()
 
 @app.post("/sync_sys_configs", description="同步线上配置到本地")
 def sync_sys_configs(params: SyncLocalConfigs):
@@ -1373,6 +1385,7 @@ def sync_sys_configs(params: SyncLocalConfigs):
         # 同步本地到线上
         url = settings.DOMAIN + "/api/ai_image/camera_machine/update_all_user_configs"
         requests.post(url=url, headers=headers, data=data_json)
+    session.close()
     return {"code": 0, "msg": "操作成功", "data": None}
 
 
@@ -1423,4 +1436,5 @@ def sync_action_configs(params: SyncLocalConfigs):
                 )
     # 因为左右脚线上id可能会发生变化  所以需要重新同步一下本地得配置信息
     # syncUserJsonConfigs(hlm_token)
+    session.close()
     return {"code": 0, "msg": "操作成功", "data": None}

+ 3 - 2
python/custom_plugins/plugins_mode/detail_generate_base.py

@@ -20,7 +20,7 @@ import threading
 from concurrent.futures import ThreadPoolExecutor
 from concurrent.futures import TimeoutError as THTimeoutError
 from middleware import UnicornException
-
+from logger import logger
 # import math
 from PIL import ImageFont
 import settings
@@ -151,9 +151,10 @@ class DetailBase(object):
         if not os.path.exists(out_path):
             return
         try:
-            shutil.rmtree(out_path)
+            shutil.rmtree(out_path,onerror=settings.handle_remove_readonly)
         except BaseException as e:
             print("删除文件夹失败", e)
+            logger.info(f"detail_generae_base 抠图前目录删除出现问题:{str(e)}")
 
     def run_all(self):
         if self.template_name:

+ 6 - 5
python/databases.py

@@ -16,11 +16,12 @@ sqlite_url = f"sqlite:///{sqlite_file_name}"
 engine = create_engine(
     sqlite_url,
     echo=False,
-    connect_args={"check_same_thread": False},  # 允许多线程访问
-    pool_size=10,
-    max_overflow=20,
-    pool_timeout=30,
-    pool_recycle=1800,
+    connect_args={"check_same_thread": False},
+    pool_size=20,        # 增加基础连接池大小
+    max_overflow=30,     # 增加最大溢出连接数
+    pool_timeout=60,     # 保持合理的超时时间
+    pool_recycle=1800,   # 连接回收时间(秒)
+    pool_pre_ping=True,  # 检查连接有效性
 )
 
 

+ 8 - 5
python/service/base.py

@@ -8,7 +8,7 @@ import shutil
 from hashlib import sha256, md5
 import requests
 from datetime import datetime
-
+from settings import handle_remove_readonly
 
 # 获取digicam的路径
 def check_install_path(other):
@@ -174,7 +174,7 @@ def get_image_mask(path):
 # 删除文件夹下的所有文件
 def remove_all_file(directory):
     try:
-        shutil.rmtree(directory)
+        shutil.rmtree(directory,onerror=handle_remove_readonly)
         os.makedirs(directory)
     except Exception as e:
         print(f'Failed to clear directory {directory}. Reason: {e}')
@@ -247,9 +247,12 @@ def check_move_goods_art_no_folder(path, goods_art_nos,limit_folder):
                 folder_list[goods_art_no] = folder_data
                 if not os.path.exists(f"{limit_folder}/{goods_art_no}"):
                     # 目标不存在
-                    folder_list[goods_art_no] = folder_data
-                    print("移动目录", folder_data["folder_path"], limit_folder)
-                    shutil.move(folder_data["folder_path"], limit_folder)
+                    try:
+                        shutil.move(folder_data["folder_path"], limit_folder)
+                        folder_list[goods_art_no] = folder_data
+                        print("移动目录", folder_data["folder_path"], limit_folder)
+                    except:
+                        continue
                 else:
                     # 如果希望覆盖
                     print(f"目标目录 {limit_folder}/{goods_art_no} 已存在,跳过移动")

+ 8 - 3
python/service/base_deal.py

@@ -23,7 +23,7 @@ import requests
 import copy, asyncio
 from settings import sendSocketMessage
 from utils.common import message_queue
-
+from logger import logger
 def sendAsyncMessage(msg="", goods_arts=[], status="",progress={}):
     """异步发送消息"""
     data = {
@@ -338,8 +338,12 @@ class BaseDealImage(object):
         is_image_deal_mode = 0
 
         # 删除目录再新建
-        if os.path.exists("{}/阴影图处理".format(folder_path)):
-            shutil.rmtree("{}/阴影图处理".format(folder_path))
+        try:
+          if os.path.exists("{}/阴影图处理".format(folder_path)):
+            shutil.rmtree("{}/阴影图处理".format(folder_path),onerror=settings.handle_remove_readonly)
+        except Exception as e:
+          print('An exception occurred')
+          logger.info(f"base deal 抠图前目录删除出现问题:{str(e)}")
 
         self.crate_all_folders(folder_path)
         print(
@@ -1169,6 +1173,7 @@ class BaseDealImage(object):
             order_by="id",
             ascending=True,
         )
+        session.close()
         if result:
             return result.goods_art_no, result.image_index, result.image_deal_mode
         else:

+ 1 - 0
python/service/deal_image.py

@@ -56,6 +56,7 @@ class DealImage(BaseDealImage):
             order_by="id",
             ascending=True,
         )
+        session.close()
         if result:
             return result.goods_art_no, result.image_index, result.image_deal_mode
         else:

+ 4 - 1
python/service/match_and_cutout_mode_control/base_deal_image_v2.py

@@ -257,8 +257,11 @@ class BaseDealImage(object):
         is_image_deal_mode = 0
 
         # 删除目录再新建
-        if os.path.exists('{}/阴影图处理'.format(folder_path)):
+        try:
+          if os.path.exists('{}/阴影图处理'.format(folder_path)):
             shutil.rmtree('{}/阴影图处理'.format(folder_path))
+        except:
+          print('An exception occurred')
 
         self.crate_all_folders(folder_path)
 

+ 6 - 1
python/settings.py

@@ -6,7 +6,7 @@ import requests
 import pillow_avif
 from utils.common import message_queue
 import hashlib
-
+import os,stat
 TIME_ZONE = pytz.timezone("Asia/Shanghai")
 from numpy import true_divide
 from databases import (
@@ -47,6 +47,7 @@ else:
             config = SysConfigs(**sys_config)
             session.add(config)
             session.commit()  # 合并事务提交
+session.close()
 # 初始化数据表---结束
 
 
@@ -65,6 +66,7 @@ def getSysConfigs(key, item, default=None):
     crud = CRUD(SysConfigs)
     one_item = crud.read(session, conditions={"key": key})
     config = json.loads(one_item.value)
+    session.close()
     if item == "image_out_format":
         default_format = config.get(item, default)
         if default_format == "" or default_format == None:
@@ -342,3 +344,6 @@ def calculate_md5(filepath):
             md5hash.update(chunk)
         # 返回MD5哈希的十六进制表示
         return md5hash.hexdigest()
+def handle_remove_readonly(func, path, exc):
+    os.chmod(path, stat.S_IWRITE)
+    func(path)

+ 5 - 1
python/sockets/connect_manager.py

@@ -27,7 +27,11 @@ class ConnectionManager:
     async def send_personal_message(self, message: str, websocket: WebSocket):
         '''向用户发送消息'''
         # await websocket.send_json(message)
-        await websocket.send_json(message)
+        try:
+          await websocket.send_json(message)
+        except Exception as e:
+          logger.info(f"socket 消息发送异常:{str(e)}")
+          await asyncio.sleep(0.001)
 
     async def broadcast(self, message: str):
         """广播消息"""

+ 29 - 4
python/sockets/message_handler.py

@@ -16,7 +16,8 @@ import settings
 from middleware import UnicornException
 from concurrent.futures import ThreadPoolExecutor
 from functools import partial
-
+from logger import logger
+import stat
 # 创建全局线程池
 executor = ThreadPoolExecutor(max_workers=4)
 async def handlerCutOut(
@@ -180,6 +181,7 @@ async def handlerSend(
                 ),
                 name="run_mcu_config",
             )
+            session.close()
         case "run_mcu_single":
             device_ctrl = DeviceControl(
                 websocket_manager=manager, smart_shooter=smart_shooter
@@ -248,6 +250,7 @@ async def handlerSend(
                 ),
                 name="run_mcu_config_single",
             )
+            session.close()
         case "get_deviation":
             device_ctrl = DeviceControl(
                 websocket_manager=manager, smart_shooter=smart_shooter
@@ -385,6 +388,7 @@ async def handlerSend(
                 ),
                 name="sendCommand",
             )
+            session.close()
         case "segment_progress":
             msg_type = "segment_progress"
             obj = None
@@ -406,10 +410,30 @@ async def handlerSend(
                 if os.path.exists(cutout_goods):
                     # 寻找当前被扣图的货号在现有目录中是否存在,如果存在先删除
                     # 重新执行抠图操作
-                    shutil.rmtree(cutout_goods)
-                    del move_folder_array[goods_art_revice]
+                    try:
+                        shutil.rmtree(cutout_goods, onerror=settings.handle_remove_readonly)
+                        del move_folder_array[goods_art_revice]
+                    except PermissionError as e:
+                        logger.info(f"抠图前目录删除出现问题:{str(e)};{goods_art_revice};{cutout_goods}")
+                        error_file_path = f"{cutout_goods}/异常说明-出现目录丢失或缺少图片请点开查看原因.txt"
+                        with open(error_file_path, 'w', encoding='utf-8') as f:
+                            f.write("目录删除失败\n")
+                            f.write(f"原因: 文件被占用或没有删除权限\n")
+                            f.write(f"错误信息: {str(e)}\n")
+                            f.write(f"时间: {time.strftime('%Y-%m-%d %H:%M:%S')}\n")
+                            f.write(f"请关闭可能正在使用此目录的程序后重试\n")
+                        continue
+                    except Exception as e:
+                        logger.info(f"抠图前目录删除出现问题:{str(e)};{goods_art_revice};{cutout_goods}")
+                        error_file_path = f"{cutout_goods}/异常说明-出现目录丢失或缺少图片请点开查看原因.txt"
+                        with open(error_file_path, 'w', encoding='utf-8') as f:
+                            f.write("目录删除失败\n")
+                            f.write(f"原因: {str(e)}\n")
+                            f.write(f"时间: {time.strftime('%Y-%m-%d %H:%M:%S')}\n")
+                            f.write(f"请检查目录状态后重试\n")
+                        continue
+            session = SqlQuery()
             for goods_art_no in goods_art_no_arrays:
-                session = SqlQuery()
                 pr = CRUD(PhotoRecord)
                 images = pr.read_all(session, conditions={"goods_art_no": goods_art_no})
                 if not images:
@@ -454,6 +478,7 @@ async def handlerSend(
                         )
                         await manager.send_personal_message(data, websocket)
                         return
+            session.close()
             # try:
             cutOutMode = (
                 "1"

+ 1 - 1
python/sockets/socket_server.py

@@ -35,7 +35,7 @@ async def updateDataRecord(PhotoFilename, id):
         # 走编辑逻辑
         record_model.updateConditions(session, conditions={"id": id}, **data)
         print(f"smart shooter 拍照记录更新成功,记录id:{id}")
-
+    session.close()
 
 @app.websocket("/ws")
 async def websocket_endpoint(websocket: WebSocket):