mirror of
https://github.com/ThearchyHelios/AgentLab.git
synced 2026-11-15 00:51:59 +00:00
定时任务小修:输入模板的字段名去掉首尾空白再存,后台通知任务的异常记日志
- 「 stat_date」原样交给运行,入口节点认不出它、必填项照样报缺:保存时去掉首尾空白,去掉后重名的拦下 - 通知扫描是另起的后台任务、没人 await:出错时异常留在任务里,只会在回收时冒出一句「从未取回的异常」。 包一层,出错记日志,下一拍照常
This commit is contained in:
@@ -116,6 +116,14 @@ async def tick(now: datetime | None = None) -> None:
|
||||
await webhook.notify_due(now)
|
||||
|
||||
|
||||
async def _notify(webhook) -> None: # noqa: ANN001 - 传进来的是 app.scheduler.webhook 模块
|
||||
"""后台跑一遍通知扫描。出错只记日志:这个任务没人 await,异常留在里面只会变成一句「从未取回的异常」。"""
|
||||
try:
|
||||
await webhook.notify_due()
|
||||
except Exception: # noqa: BLE001
|
||||
logger.exception("定时任务的通知推送这一拍出错,下一拍照常进行")
|
||||
|
||||
|
||||
class _Runner:
|
||||
"""调度循环的任务。照 sandbox/manager.py 回收闲置会话的写法:一个 asyncio 任务,出错记日志接着下一拍。"""
|
||||
|
||||
@@ -142,7 +150,7 @@ class _Runner:
|
||||
try:
|
||||
await fire_due()
|
||||
if self.notify is None or self.notify.done():
|
||||
self.notify = asyncio.create_task(webhook.notify_due(), name="agentlab-scheduler-notify")
|
||||
self.notify = asyncio.create_task(_notify(webhook), name="agentlab-scheduler-notify")
|
||||
except asyncio.CancelledError:
|
||||
raise
|
||||
except Exception: # noqa: BLE001 - 这一拍出错不该让循环停下
|
||||
|
||||
@@ -107,13 +107,19 @@ def check_template(template: Any) -> dict[str, str]:
|
||||
return {}
|
||||
if not isinstance(template, dict):
|
||||
raise TemplateError("输入模板需要是「字段名:模板」的对象,例如 stat_date 对应 {{ schedule.yesterday }}")
|
||||
for name, text in template.items():
|
||||
if not isinstance(name, str) or not name.strip():
|
||||
out: dict[str, str] = {}
|
||||
for raw, text in template.items():
|
||||
# 字段名去掉首尾空白再存:「 stat_date」交给运行,入口节点认不出它,必填项照样报缺
|
||||
name = raw.strip() if isinstance(raw, str) else ""
|
||||
if not name:
|
||||
raise TemplateError("输入模板里有空的字段名,请填写工作流的输入字段名")
|
||||
if name in out:
|
||||
raise TemplateError(f"输入模板里字段「{name}」写了两次,请只保留一个")
|
||||
if not isinstance(text, str):
|
||||
raise TemplateError(f"输入「{name}」的值需要是文本(可以带 {{{{ schedule.yesterday }}}} 这样的变量),当前为「{text}」")
|
||||
_check_text(name, text)
|
||||
return dict(template)
|
||||
out[name] = text
|
||||
return out
|
||||
|
||||
|
||||
def _check_text(name: str, text: str) -> None:
|
||||
|
||||
@@ -124,6 +124,13 @@ def test_bad_templates_explain_in_chinese(template, fragments):
|
||||
assert fragment in str(caught.value), str(caught.value)
|
||||
|
||||
|
||||
def test_field_names_are_trimmed_and_unique():
|
||||
assert service.check_template({" stat_date ": "{{ schedule.yesterday }}"}) == {"stat_date": "{{ schedule.yesterday }}"}
|
||||
with pytest.raises(TemplateError) as caught:
|
||||
service.check_template({"stat_date": "a", "stat_date ": "b"})
|
||||
assert "stat_date" in str(caught.value) and "两次" in str(caught.value)
|
||||
|
||||
|
||||
def test_variable_catalog():
|
||||
items = service.variables(datetime(2026, 10, 5, 1, 0, tzinfo=UTC), "Asia/Shanghai")
|
||||
names = [i["name"] for i in items]
|
||||
|
||||
Reference in New Issue
Block a user