144 lines
4.3 KiB
Python
144 lines
4.3 KiB
Python
#!/usr/bin/env python
|
|
# -*- coding: utf-8 -*-
|
|
"""
|
|
延时节点处理器
|
|
处理流程延时等待
|
|
"""
|
|
import logging
|
|
from datetime import datetime, timedelta
|
|
from typing import Dict, TYPE_CHECKING
|
|
|
|
from online_dev.workflow.engine.handlers.base_handler import BaseNodeHandler
|
|
|
|
if TYPE_CHECKING:
|
|
from online_dev.workflow.engine.base import ExecutionContext
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class DelayNodeHandler(BaseNodeHandler):
|
|
"""
|
|
延时节点处理器
|
|
|
|
支持延时单位:
|
|
- minute: 分钟
|
|
- hour: 小时
|
|
- day: 天
|
|
- workday: 工作日(跳过周六日)
|
|
"""
|
|
|
|
async def execute(self, context: 'ExecutionContext', node: Dict) -> None:
|
|
"""
|
|
执行延时节点:计算到期时间,注册定时任务
|
|
"""
|
|
node_id = self.get_node_id(node)
|
|
node_name = self.get_node_name(node)
|
|
node_config = self.get_node_config(node)
|
|
|
|
duration = node_config.get('duration', 1)
|
|
unit = node_config.get('unit', 'hour')
|
|
|
|
unit_names = {
|
|
'minute': '分钟',
|
|
'hour': '小时',
|
|
'day': '天',
|
|
'workday': '工作日',
|
|
}
|
|
unit_name = unit_names.get(unit, unit)
|
|
|
|
logger.info(f"延时节点 - 等待 {duration} {unit_name}")
|
|
|
|
# 更新实例当前节点
|
|
await self.update_instance_node(context, node)
|
|
|
|
# 计算到期时间
|
|
delay_until = self._calculate_delay_until(duration, unit)
|
|
|
|
# 更新实例延时状态
|
|
context.instance.delay_node_id = node_id
|
|
context.instance.delay_until = delay_until
|
|
context.db.add(context.instance)
|
|
await context.db.flush()
|
|
|
|
# 记录延时开始日志
|
|
await self.create_log(
|
|
context, node, 'delay_start',
|
|
comment=f'开始延时等待 {duration} {unit_name},预计 {delay_until.strftime("%Y-%m-%d %H:%M:%S")} 恢复',
|
|
extra_data={
|
|
'duration': duration,
|
|
'unit': unit,
|
|
'delay_until': delay_until.isoformat(),
|
|
},
|
|
operator_id='',
|
|
)
|
|
|
|
# 注册定时任务
|
|
from online_dev.workflow.engine.delay_callback import _register_delay_job
|
|
|
|
instance_id = str(context.instance.id)
|
|
success = await _register_delay_job(instance_id, node_id, delay_until)
|
|
|
|
if not success:
|
|
# 调度器不可用时,直接跳过延时继续推进(降级处理)
|
|
logger.warning(f"调度器不可用,延时节点直接跳过: instance={instance_id}, node={node_id}")
|
|
|
|
# 清除延时状态
|
|
context.instance.delay_node_id = ""
|
|
context.instance.delay_until = None
|
|
context.db.add(context.instance)
|
|
await context.db.flush()
|
|
|
|
await self.create_log(
|
|
context, node, 'delay_skip',
|
|
comment='调度器不可用,延时跳过',
|
|
operator_id='',
|
|
)
|
|
await self.advance_to_next(context, node)
|
|
|
|
@staticmethod
|
|
def _calculate_delay_until(duration: int, unit: str) -> datetime:
|
|
"""
|
|
计算延时到期时间
|
|
|
|
Args:
|
|
duration: 延时时长
|
|
unit: 延时单位 (minute/hour/day/workday)
|
|
|
|
Returns:
|
|
到期时间
|
|
"""
|
|
now = datetime.now()
|
|
|
|
if unit == 'minute':
|
|
return now + timedelta(minutes=duration)
|
|
elif unit == 'hour':
|
|
return now + timedelta(hours=duration)
|
|
elif unit == 'day':
|
|
return now + timedelta(days=duration)
|
|
elif unit == 'workday':
|
|
return DelayNodeHandler._add_workdays(now, duration)
|
|
else:
|
|
# 默认按小时处理
|
|
return now + timedelta(hours=duration)
|
|
|
|
@staticmethod
|
|
def _add_workdays(start: datetime, days: int) -> datetime:
|
|
"""
|
|
添加工作日(跳过周六日)
|
|
|
|
Args:
|
|
start: 起始时间
|
|
days: 工作日天数
|
|
|
|
Returns:
|
|
目标时间(保持原始时分秒)
|
|
"""
|
|
current = start
|
|
added = 0
|
|
while added < days:
|
|
current += timedelta(days=1)
|
|
# weekday(): 0=周一, 5=周六, 6=周日
|
|
if current.weekday() < 5:
|
|
added += 1
|
|
return current
|