Skip to content

Commit c9504f2

Browse files
committed
feat: Support cron expression in trigger
1 parent c61e823 commit c9504f2

File tree

7 files changed

+84
-19
lines changed

7 files changed

+84
-19
lines changed

apps/locales/en_US/LC_MESSAGES/django.po

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9153,4 +9153,16 @@ msgid "Share link does not exist"
91539153
msgstr "Share link does not exist"
91549154

91559155
msgid "Chat has been deleted"
9156-
msgstr "Chat has been deleted"
9156+
msgstr "Chat has been deleted"
9157+
9158+
msgid "cron type requires cron_expression field"
9159+
msgstr "cron type requires cron_expression field"
9160+
9161+
msgid "Invalid cron expression: %s"
9162+
msgstr "Invalid cron expression: %s"
9163+
9164+
msgid "Batch Remove Documents from Tag"
9165+
msgstr "Batch Remove Documents from Tag"
9166+
9167+
msgid "Document does not belong to current knowledge"
9168+
msgstr "Document does not belong to current knowledge"

apps/locales/zh_CN/LC_MESSAGES/django.po

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9276,4 +9276,16 @@ msgid "Share link does not exist"
92769276
msgstr "分享链接不存在"
92779277

92789278
msgid "Chat has been deleted"
9279-
msgstr "聊天记录已被删除"
9279+
msgstr "聊天记录已被删除"
9280+
9281+
msgid "cron type requires cron_expression field"
9282+
msgstr "cron 类型需要 cron_expression 字段"
9283+
9284+
msgid "Invalid cron expression: %s"
9285+
msgstr "Cron 表达式不合法:%s"
9286+
9287+
msgid "Batch Remove Documents from Tag"
9288+
msgstr "批量删除标签下的文档"
9289+
9290+
msgid "Document does not belong to current knowledge"
9291+
msgstr "文档不属于当前知识库"

apps/locales/zh_Hant/LC_MESSAGES/django.po

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9273,4 +9273,16 @@ msgid "Share link does not exist"
92739273
msgstr "分享連結不存在"
92749274

92759275
msgid "Chat has been deleted"
9276-
msgstr "聊天記錄已被刪除"
9276+
msgstr "聊天記錄已被刪除"
9277+
9278+
msgid "cron type requires cron_expression field"
9279+
msgstr "cron 類型需要 cron_expression 欄位"
9280+
9281+
msgid "Invalid cron expression: %s"
9282+
msgstr "Cron 表達式不合法:%s"
9283+
9284+
msgid "Batch Remove Documents from Tag"
9285+
msgstr "批量刪除標籤下的文件"
9286+
9287+
msgid "Document does not belong to current knowledge"
9288+
msgstr "文件不屬於當前知識庫"

apps/trigger/handler/impl/trigger/scheduled_trigger.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
# coding=utf-8
2-
32
from django.db.models import QuerySet
43

54
from common.utils.logger import maxkb_logger
@@ -132,6 +131,30 @@ def _deploy_monthly(trigger: dict, trigger_tasks: list[dict], setting: dict, tri
132131
replace_existing=True,
133132
)
134133

134+
def _deploy_cron(trigger: dict, trigger_tasks: list[dict], setting: dict, trigger_id: str) -> None:
135+
from common.job import scheduler
136+
from apscheduler.triggers.cron import CronTrigger
137+
138+
cron_expression = setting.get('cron_expression')
139+
if not cron_expression:
140+
maxkb_logger.warning(f"empty cron_expression, trigger_id={trigger_id}")
141+
return
142+
143+
try:
144+
cron_trigger = CronTrigger.from_crontab(cron_expression.strip())
145+
except ValueError:
146+
maxkb_logger.warning(f"invalid cron_expression={cron_expression}, trigger_id={trigger_id}")
147+
return
148+
149+
for task in trigger_tasks:
150+
job_id = f"trigger:{trigger_id}:task:{task['id']}:cron:{cron_expression.strip()}"
151+
scheduler.add_job(
152+
ScheduledTrigger.execute,
153+
trigger=cron_trigger,
154+
id=job_id,
155+
kwargs={"trigger": trigger, "trigger_task": task},
156+
replace_existing=True,
157+
)
135158

136159
def _deploy_interval(trigger: dict, trigger_tasks: list[dict], setting: dict, trigger_id: str) -> None:
137160
from common.job import scheduler
@@ -184,6 +207,7 @@ def deploy_scheduled_trigger(trigger: dict, trigger_tasks: list[dict], setting:
184207
"weekly": _deploy_weekly,
185208
"monthly": _deploy_monthly,
186209
"interval": _deploy_interval,
210+
'cron': _deploy_cron
187211
}
188212
fn = deployers.get(schedule_type)
189213
if not fn:

apps/trigger/serializers/task_source_trigger.py

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,26 +6,16 @@
66
@date:2026/1/22 16:18
77
@desc:
88
"""
9-
import os.path
10-
import re
119
from typing import Dict
1210

13-
import uuid_utils.compat as uuid
14-
from django.core import validators
15-
from django.db import models, transaction
11+
from django.db import transaction
1612
from django.db.models import QuerySet
1713
from django.utils.translation import gettext_lazy as _
1814
from rest_framework import serializers
1915

2016
from application.models import Application
21-
from common.db.search import page_search, get_dynamics_model, native_page_search, native_search
2217
from common.exception.app_exception import AppApiException
23-
from common.field.common import ObjectField
24-
from common.utils.common import get_file_content
25-
from knowledge.serializers.common import BatchSerializer
26-
from maxkb.conf import PROJECT_DIR
2718
from tools.models import Tool
28-
from tools.serializers.tool import ToolModelSerializer
2919
from trigger.models import TriggerTypeChoices, Trigger, TriggerTaskTypeChoices, TriggerTask
3020
from trigger.serializers.trigger import TriggerModelSerializer, TriggerSerializer, ApplicationTriggerTaskSerializer, \
3121
ToolTriggerTaskSerializer, TriggerTaskModelSerializer

apps/trigger/serializers/trigger.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ def _validate_time_format(time_str):
160160
def _validate_scheduled_setting(self, setting):
161161
schedule_type = setting.get('schedule_type')
162162

163-
valid_types = ['daily', 'weekly', 'monthly', 'interval']
163+
valid_types = ['daily', 'weekly', 'monthly', 'interval','cron']
164164
if schedule_type not in valid_types:
165165
raise serializers.ValidationError(
166166
{'trigger_setting': _('schedule_type must be one of %s') % ', '.join(valid_types)
@@ -173,7 +173,8 @@ def _validate_scheduled_setting(self, setting):
173173
self._validate_monthly(setting)
174174
elif schedule_type == 'interval':
175175
self._validate_interval(setting)
176-
176+
elif schedule_type == 'cron':
177+
self._validate_cron(setting)
177178
def _validate_daily(self, setting):
178179
self._validate_required_field(setting, 'time', 'daily')
179180
self._validate_time_array(setting['time'])
@@ -212,6 +213,21 @@ def _validate_interval(self, setting):
212213
raise serializers.ValidationError({
213214
'trigger_setting': _('interval_unit must be one of %s') % ', '.join(valid_units)
214215
})
216+
@staticmethod
217+
def _validate_cron(setting):
218+
from apscheduler.triggers.cron import CronTrigger
219+
220+
cron_expression: str = setting.get('cron_expression')
221+
if not cron_expression:
222+
raise serializers.ValidationError({
223+
'trigger_setting': _('cron type requires cron_expression field')
224+
})
225+
try:
226+
CronTrigger.from_crontab(cron_expression.strip())
227+
except ValueError:
228+
raise serializers.ValidationError({
229+
'trigger_setting': _('Invalid cron expression: %s') % cron_expression
230+
})
215231

216232
@staticmethod
217233
def _validate_event_setting(setting):

apps/trigger/views/trigger_task.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,7 @@
1717
from trigger.api.trigger_task import TriggerTaskRecordExecutionDetailsAPI, TriggerTaskRecordPageAPI, TriggerTaskAPI
1818
from trigger.serializers.trigger_task import TriggerTaskQuerySerializer, TriggerTaskRecordQuerySerializer, \
1919
TriggerTaskRecordOperateSerializer
20-
from common.constants.permission_constants import PermissionConstants, RoleConstants, ViewPermission, CompareConstants, \
21-
Permission, Group, Operate
20+
from common.constants.permission_constants import PermissionConstants, RoleConstants
2221

2322

2423
class TriggerTaskView(APIView):

0 commit comments

Comments
 (0)