From 1072e900709b1c5b4b3a6f47552567536ac5060d Mon Sep 17 00:00:00 2001 From: Yu Yon Date: Fri, 12 Dec 2025 10:12:27 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=AE=9A=E6=97=B6=E4=BB=BB?= =?UTF-8?q?=E5=8A=A1=E9=9A=8F=E6=9C=BA=E6=97=B6=E9=97=B4=E6=89=A7=E8=A1=8C?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=EF=BC=9B=E4=BF=AE=E5=A4=8D=E6=89=8B=E5=8A=A8?= =?UTF-8?q?=E6=89=A7=E8=A1=8C=E4=BB=BB=E5=8A=A1=E4=B8=8D=E5=8F=91=E9=80=81?= =?UTF-8?q?=E9=82=AE=E4=BB=B6=E9=80=9A=E7=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app.py | 65 ++++++++++++++++++++++++++++++++++++-------- database.py | 10 +++---- templates/index.html | 13 +++++++-- 3 files changed, 69 insertions(+), 19 deletions(-) diff --git a/app.py b/app.py index 727d77b..d873586 100755 --- a/app.py +++ b/app.py @@ -132,6 +132,10 @@ log_cache_total_count = 0 # 全局日志总数,防止无限增长 batch_task_screenshots = {} # {batch_id: {'user_id': x, 'browse_type': y, 'screenshots': [{'account_name': a, 'path': p, 'items': n, 'attachments': m}], 'total_accounts': n, 'completed': n}} batch_task_lock = threading.Lock() +# 随机延迟任务存储 +pending_random_schedules = {} +pending_random_lock = threading.Lock() + # 日志缓存限制 MAX_LOGS_PER_USER = config.MAX_LOGS_PER_USER # 每个用户最多100条 MAX_TOTAL_LOGS = config.MAX_TOTAL_LOGS # 全局最多1000条,防止内存泄漏 @@ -2181,12 +2185,14 @@ def run_task(user_id, account_id, browse_type, enable_screenshot=True, source="m source=source ) # 发送任务完成邮件通知(不截图时在此发送) - try: - user_info = database.get_user_by_id(user_id) - # 检查用户是否开启了邮件通知 - if user_info and user_info.get('email') and database.get_user_email_notify(user_id): - account_name = account.remark if account.remark else account.username - email_service.send_task_complete_email_async( + # 只对定时任务发送邮件通知,手动执行不发送 + if source and source.startswith('user_scheduled'): + try: + user_info = database.get_user_by_id(user_id) + # 检查用户是否开启了邮件通知 + if user_info and user_info.get('email') and database.get_user_email_notify(user_id): + account_name = account.remark if account.remark else account.username + email_service.send_task_complete_email_async( user_id=user_id, email=user_info['email'], username=user_info['username'], @@ -2197,8 +2203,8 @@ def run_task(user_id, account_id, browse_type, enable_screenshot=True, source="m screenshot_path=None, log_callback=lambda msg: log_to_client(msg, user_id, account_id) ) - except Exception as email_error: - logger.warning(f"发送任务完成邮件失败: {email_error}") + except Exception as email_error: + logger.warning(f"发送任务完成邮件失败: {email_error}") # 成功则跳出重试循环 break else: @@ -2599,8 +2605,8 @@ def take_screenshot_for_account(user_id, account_id, browse_type="应读", sourc print(f"[批次邮件] 已发送打包邮件,包含 {len(batch_info['screenshots'])} 个截图") except Exception as batch_email_err: print(f"[批次邮件] 发送失败: {batch_email_err}") - else: - # 非批次任务:直接发送邮件(保持原有逻辑) + elif source and source.startswith('user_scheduled'): + # 非批次的定时任务:直接发送邮件(手动执行不发送邮件通知) user_info = database.get_user_by_id(user_id) if user_info and user_info.get('email') and database.get_user_email_notify(user_id): email_service.send_task_complete_email_async( @@ -3683,8 +3689,43 @@ def scheduled_task_worker(): h, m = schedule_time.split(':') schedule_time = f"{int(h):02d}:{int(m):02d}" - # 检查时间是否匹配 - if schedule_time != current_time: + # 获取随机延迟设置 + random_delay = schedule_config.get('random_delay', 0) + + # 处理随机延迟逻辑 + should_execute = False + if random_delay == 1: + import random as rand_module + with pending_random_lock: + if schedule_id in pending_random_schedules: + # 检查是否到达随机执行时间 + pending_info = pending_random_schedules[schedule_id] + scheduled_for = pending_info['scheduled_for'] + if now >= scheduled_for: + del pending_random_schedules[schedule_id] + should_execute = True + print(f"[定时任务] 任务#{schedule_id} 随机延迟到达,开始执行") + else: + # 计算窗口时间 + set_hour, set_minute = map(int, schedule_time.split(':')) + set_time_today = now.replace(hour=set_hour, minute=set_minute, second=0, microsecond=0) + window_start = set_time_today - timedelta(minutes=15) + + # 当前时间刚好到达窗口开始 + if now.strftime('%H:%M') == window_start.strftime('%H:%M'): + random_minutes = rand_module.randint(0, 30) + random_time = window_start + timedelta(minutes=random_minutes) + pending_random_schedules[schedule_id] = { + 'scheduled_for': random_time, + 'config': schedule_config + } + print(f"[定时任务] 任务#{schedule_id} 安排随机时间: {random_time.strftime('%H:%M')}") + else: + # 精确时间匹配 + if schedule_time == current_time: + should_execute = True + + if not should_execute: continue # 检查星期是否匹配 diff --git a/database.py b/database.py index 1b38dbe..0228e04 100755 --- a/database.py +++ b/database.py @@ -1738,7 +1738,7 @@ def get_schedule_by_id(schedule_id): def create_user_schedule(user_id, name='我的定时任务', schedule_time='08:00', weekdays='1,2,3,4,5', browse_type='应读', - enable_screenshot=1, account_ids=None): + enable_screenshot=1, account_ids=None, random_delay=0): """创建用户定时任务""" import json with db_pool.get_db() as conn: @@ -1751,10 +1751,10 @@ def create_user_schedule(user_id, name='我的定时任务', schedule_time='08:0 cursor.execute(''' INSERT INTO user_schedules ( user_id, name, enabled, schedule_time, weekdays, - browse_type, enable_screenshot, account_ids, created_at, updated_at - ) VALUES (?, ?, 0, ?, ?, ?, ?, ?, ?, ?) + browse_type, enable_screenshot, account_ids, random_delay, created_at, updated_at + ) VALUES (?, ?, 0, ?, ?, ?, ?, ?, ?, ?, ?) ''', (user_id, name, schedule_time, weekdays, browse_type, - enable_screenshot, account_ids_str, cst_time, cst_time)) + enable_screenshot, account_ids_str, random_delay, cst_time, cst_time)) conn.commit() return cursor.lastrowid @@ -1771,7 +1771,7 @@ def update_user_schedule(schedule_id, **kwargs): params = [] allowed_fields = ['name', 'enabled', 'schedule_time', 'weekdays', - 'browse_type', 'enable_screenshot', 'account_ids'] + 'browse_type', 'enable_screenshot', 'account_ids', 'random_delay'] for field in allowed_fields: if field in kwargs: diff --git a/templates/index.html b/templates/index.html index 54e6521..cbeaac6 100644 --- a/templates/index.html +++ b/templates/index.html @@ -710,6 +710,13 @@
+
+ +
勾选后将在设定时间前后15分钟内随机执行
+