This commit is contained in:
dongchangxi committed 2025-12-09 11:09:11 +08:00
1 parent 5134ece73b
commit dcf9eb6f23
13 files changed
+972 -30

No files matched your search

+1
View File
@@ -56,3 +56,4 @@ echo ========================================
pause
+1
View File
@@ -149,3 +149,4 @@ if __name__ == '__main__':
sys.exit(1)
+158
View File
@@ -0,0 +1,158 @@
import os,shutil
import redis
import oss2,time,sys
import requests
import argparse,json
from utils.funcs import requestApiToUpdateSliceStatus
# 将当前脚本所在目录添加到 Python 路径,以便导入 utils 模块
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
# from download_print_out import download_transform_save_by_json
from utils.oss_redis import redisClient
from utils.funcs import downloadJsonAndJpgFileAndMoveToCorrectDir, downloadDataByOssAndTransformSave
# 默认使用脚本所在目录
currentDir = os.path.dirname(os.path.abspath(__file__))
ENV = 'prod'
url = 'https://mp.api.suwa3d.com'
if ENV == 'dev':
url = 'http://mp.api.dev.com'
elif ENV == 'prod':
url = 'https://mp.api.suwa3d.com'
#判断是否上传了 JSON 文件
def step1(versionId):
# 下载json 文件 和 图片
dirName,machineInfo = downloadJsonAndJpgFileAndMoveToCorrectDir(versionId,currentDir)
if not dirName:
return False
#判断是否是小机台
isSmallMachine = False
if str(machineInfo["machine_type"]) == '1':
isSmallMachine = True
#下载数据,转换数据
res = downloadDataByOssAndTransformSave(dirName,isSmallMachine)
if not res:
return False
#判断下载的obj文件数量和json里的是否一致,排除arrange文件夹
objFilePath = os.path.join(dirName, 'data')
objCounts = 0
for file in os.listdir(objFilePath):
if file == 'arrange':
continue
if file.endswith('.obj'):
objCounts += 1
print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} 下载处理完成的obj文件数量: {objCounts}')
# requestApiToUpdateSliceStatus(versionId,objCounts)
# 读取 队列中一个数据出来
def main(work_dir=None, batch_id=None):
global currentDir
# 如果指定了工作目录,使用指定的目录
if work_dir:
work_dir = os.path.abspath(work_dir)
if not os.path.exists(work_dir):
print(f'指定的工作目录不存在: {work_dir},将创建该目录')
os.makedirs(work_dir, exist_ok=True)
currentDir = work_dir
print(f'使用指定的工作目录: {currentDir}')
else:
print(f'没有指定工作目录,退出')
exit(0)
versionId = str(batch_id)
print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} 正在处理版次ID={versionId}')
res = step1(versionId)
if res == False:
print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} JSON文件下载数据失败,等待10秒')
# time.sleep(10)
# continue
# 循环处理,直到队列为空
# try:
# while True:
# try:
# r = redisClient()
# #检测队列是否有值
# if r.scard('pb:sliceing') == 0:
# print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} 队列为空,等待10秒')
# time.sleep(10)
# continue
# #获取队列中的值
# data = r.spop('pb:sliceing')
# if data is None:
# print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} 取出的数据为空,等待10秒')
# time.sleep(10)
# continue
# data = data.decode('utf-8')
# #判断是否是数字
# if not data.isdigit():
# print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} 取出的数据不是数字,等待10秒')
# time.sleep(10)
# continue
# versionId = str(data)
# print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} 正在处理版次ID={versionId}')
# res = step1(versionId)
# if res == False:
# print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} JSON文件下载数据失败,等待10秒')
# time.sleep(10)
# continue
# # 在长时间操作后,确保 Redis 连接仍然有效
# # 通过重新获取客户端来触发连接检查
# try:
# r = redisClient()
# r.ping() # 测试连接
# except Exception as e:
# print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} Redis连接检查失败: {str(e)},将在下次循环时自动重连')
# #time.sleep(10)
# except KeyboardInterrupt:
# # 在循环内部捕获 KeyboardInterrupt,允许在 sleep 或操作中被中断
# raise # 重新抛出,让外层捕获
# except KeyboardInterrupt:
# print(f'\n{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} 收到中断信号,正在优雅退出...')
# print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} 程序已停止')
# sys.exit(0)
def testMain():
global currentDir
currentDir = "/Users/dcx/code/make2/script/factory_sliceing_v2/tempData"
versionId = '10153' #'10153 10158'
print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} 正在处理版次ID={versionId}')
res = step1(versionId)
print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} 处理完成,res={res}')
if __name__ == '__main__':
#testMain() 新增参数 batchId
parser = argparse.ArgumentParser(description='排版打印订单处理程序')
parser.add_argument(
'--work-dir',
type=str,
default=None,
help='指定工作目录(磁盘路径),例如: D:/work 或 /Users/username/work。如果不指定,则使用脚本所在目录'
)
parser.add_argument(
'--batch—id',
type=str,
default=None,
help='指定批次ID'
)
args = parser.parse_args()
main(work_dir=args.work_dir, batch_id=args.batch_id)
@@ -4,3 +4,4 @@ requests>=2.28.0
pyinstaller>=5.0.0
+76 -30
View File
@@ -1,4 +1,10 @@
import oss2,redis
import time
import logging
# 配置日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
# 连接oss - 单例模式
class OSSClientSingleton:
@@ -29,47 +35,87 @@ class RedisClientSingleton:
_instance = None
_client = None
# Redis连接配置
REDIS_CONFIG = {
'host': 'mp.api.suwa3d.com',
'password': 'kcV2000',
'port': 6379,
'db': 6,
'socket_timeout': 30, # 操作超时30秒
'socket_connect_timeout': 10, # 连接超时10秒
'socket_keepalive': True, # 启用 TCP keepalive
'socket_keepalive_options': {}, # keepalive 选项
'health_check_interval': 30 # 健康检查间隔30秒
}
# 重试配置
RETRY_INTERVAL = 5 # 重试间隔(秒)
MAX_RETRY_INTERVAL = 60 # 最大重试间隔(秒),用于指数退避
def __new__(cls):
if cls._instance is None:
cls._instance = super(RedisClientSingleton, cls).__new__(cls)
return cls._instance
def _create_redis_client(self):
"""创建Redis客户端"""
return redis.Redis(**self.REDIS_CONFIG)
def _connect_with_retry(self, max_retries=None, retry_interval=None):
"""
带重试机制的Redis连接方法
:param max_retries: 最大重试次数,None表示无限重试
:param retry_interval: 重试间隔(秒),None表示使用默认值,支持指数退避
:return: Redis客户端实例
"""
if retry_interval is None:
retry_interval = self.RETRY_INTERVAL
retry_count = 0
current_interval = retry_interval
while True:
try:
logger.info(f"尝试连接Redis (第 {retry_count + 1} 次)...")
client = self._create_redis_client()
# 测试连接
client.ping()
logger.info("Redis连接成功!")
return client
except (redis.ConnectionError, redis.TimeoutError, AttributeError, Exception) as e:
retry_count += 1
error_msg = str(e)
logger.warning(f"Redis连接失败 (第 {retry_count} 次): {error_msg}")
# 如果设置了最大重试次数且已达到,则抛出异常
if max_retries is not None and retry_count >= max_retries:
logger.error(f"达到最大重试次数 {max_retries},停止重试")
raise
# 指数退避:每次重试间隔逐渐增加,但不超过最大值
logger.info(f"等待 {current_interval} 秒后重试...")
time.sleep(current_interval)
current_interval = min(current_interval * 1.5, self.MAX_RETRY_INTERVAL)
def get_client(self):
"""
获取Redis客户端,如果连接断开则自动重连(带重试机制)
:return: Redis客户端实例
"""
if self._client is None:
# 添加超时参数,防止连接超时
# socket_timeout: 每次操作的超时时间(秒)
# socket_connect_timeout: 连接超时时间(秒)
# socket_keepalive: 启用 TCP keepalive
# socket_keepalive_options: keepalive 选项
self._client = redis.Redis(
host='mp.api.suwa3d.com',
password='kcV2000',
port=6379,
db=6,
socket_timeout=30, # 操作超时30秒
socket_connect_timeout=10, # 连接超时10秒
socket_keepalive=True, # 启用 TCP keepalive
socket_keepalive_options={}, # keepalive 选项
health_check_interval=30 # 健康检查间隔30秒
)
# 首次连接,使用无限重试直到成功
logger.info("初始化Redis连接...")
self._client = self._connect_with_retry(max_retries=None)
else:
# 检查连接是否有效,如果断开则重新连接
# 检查连接是否有效,如果断开则重新连接(带重试)
try:
self._client.ping()
except (redis.ConnectionError, redis.TimeoutError, AttributeError):
# 连接断开,重新创建连接
except (redis.ConnectionError, redis.TimeoutError, AttributeError) as e:
# 连接断开,重新创建连接(使用无限重试直到成功)
logger.warning(f"Redis连接已断开: {str(e)},开始重新连接...")
self._client = None
self._client = redis.Redis(
host='mp.api.suwa3d.com',
password='kcV2000',
port=6379,
db=6,
socket_timeout=30,
socket_connect_timeout=10,
socket_keepalive=True,
socket_keepalive_options={},
health_check_interval=30
)
self._client = self._connect_with_retry(max_retries=None)
return self._client