Răsfoiți Sursa

优化定时任务修改启动

SpringSunYY 5 luni în urmă
părinte
comite
efb11a2c59

+ 5 - 3
ruoyi_apscheduler/domain/entity.py

@@ -9,6 +9,7 @@ from typing_extensions import Annotated
 from ruoyi_common.base.model import BaseEntity, AuditEntity
 from ruoyi_common.base.model import BaseEntity, AuditEntity
 from ruoyi_common.base.transformer import str_to_int, to_datetime
 from ruoyi_common.base.transformer import str_to_int, to_datetime
 from ruoyi_common.base.schema_vo import VoAccess
 from ruoyi_common.base.schema_vo import VoAccess
+from ruoyi_common.utils.base import DateUtil
 from ruoyi_apscheduler.constant import DATETIME_FORMAT
 from ruoyi_apscheduler.constant import DATETIME_FORMAT
 
 
 
 
@@ -51,14 +52,14 @@ class SysJob(AuditEntity):
     # 创建时间
     # 创建时间
     create_time: Annotated[
     create_time: Annotated[
         Optional[datetime],
         Optional[datetime],
-        BeforeValidator(to_datetime(DATETIME_FORMAT)),
+        BeforeValidator(to_datetime([DATETIME_FORMAT, DateUtil.YYYY_MM_DD_HH_MM_SS])),
         Field(default=None,vo=VoAccess(body=False))
         Field(default=None,vo=VoAccess(body=False))
     ]
     ]
     
     
     # 更新时间
     # 更新时间
     update_time: Annotated[
     update_time: Annotated[
         Optional[datetime],
         Optional[datetime],
-        BeforeValidator(to_datetime(DATETIME_FORMAT)),
+        BeforeValidator(to_datetime([DATETIME_FORMAT, DateUtil.YYYY_MM_DD_HH_MM_SS])),
         Field(default=None,vo=VoAccess(body=False))
         Field(default=None,vo=VoAccess(body=False))
     ]
     ]
     
     
@@ -71,7 +72,8 @@ class SysJobLog(BaseEntity):
     
     
     job_log_id: Annotated[
     job_log_id: Annotated[
         Optional[int],
         Optional[int],
-        BeforeValidator(str_to_int)
+        BeforeValidator(str_to_int),
+        Field(default=None)
     ]
     ]
     
     
     job_name: Annotated[
     job_name: Annotated[

+ 6 - 1
ruoyi_apscheduler/service/job.py

@@ -169,7 +169,12 @@ class SysJobService:
         job.status = ScheduleStatus.NORMAL.value
         job.status = ScheduleStatus.NORMAL.value
         num = SysJobMapper.update_job(job)
         num = SysJobMapper.update_job(job)
         if num > 0:
         if num > 0:
-            scheduler.pause_job(job.job_key)
+            sched_job = scheduler.get_job(job.job_key)
+            if not sched_job:
+                # APScheduler 中不存在该任务时重新创建
+                ScheduleUtil.create_schedule_job(scheduler, job)
+            else:
+                scheduler.resume_job(job.job_key)
         return num
         return num
     
     
     @classmethod
     @classmethod

+ 47 - 2
ruoyi_common/base/reqparser.py

@@ -1,9 +1,9 @@
 
 
 from abc import ABC, abstractmethod
 from abc import ABC, abstractmethod
 from dataclasses import dataclass
 from dataclasses import dataclass
-from typing import ClassVar, Dict
+from typing import ClassVar, Dict, Iterable, Set, Type
 from flask import g, request
 from flask import g, request
-from pydantic import BaseModel
+from pydantic import AliasChoices, AliasPath, BaseModel
 from werkzeug.datastructures import ImmutableMultiDict
 from werkzeug.datastructures import ImmutableMultiDict
 from werkzeug.exceptions import BadRequest,UnsupportedMediaType
 from werkzeug.exceptions import BadRequest,UnsupportedMediaType
 
 
@@ -89,20 +89,65 @@ class QueryReqParser(BaseReqParser):
             page = PageModel.model_validate(data,context=self.context)
             page = PageModel.model_validate(data,context=self.context)
             if page.model_fields_set:
             if page.model_fields_set:
                 self.criterian_meta.page = page
                 self.criterian_meta.page = page
+            self._remove_model_aliases(data, PageModel)
         if self.context.is_sort:
         if self.context.is_sort:
             sort = OrderModel.model_validate(data,context=self.context)
             sort = OrderModel.model_validate(data,context=self.context)
             if sort.model_fields_set:
             if sort.model_fields_set:
                 self.criterian_meta.sort = sort
                 self.criterian_meta.sort = sort
+            self._remove_model_aliases(data, OrderModel)
         if self.extra_model:
         if self.extra_model:
             extra = self.extra_model.model_validate(data,context=self.context)
             extra = self.extra_model.model_validate(data,context=self.context)
             if extra.model_fields_set:
             if extra.model_fields_set:
                 self.criterian_meta.extra = extra
                 self.criterian_meta.extra = extra
+            self._remove_model_aliases(data, self.extra_model)
         return data
         return data
     
     
     def cast_model(self, bo_model:BaseEntity) -> BaseModel:
     def cast_model(self, bo_model:BaseEntity) -> BaseModel:
         data = self.data()
         data = self.data()
         bo = bo_model.model_validate(data)
         bo = bo_model.model_validate(data)
         return bo
         return bo
+
+    def _remove_model_aliases(
+        self,
+        data: Dict[str, str],
+        model_cls: Type[BaseModel]
+    ) -> None:
+        """
+        删除已经用于解析的模型字段别名,避免后续模型校验时报额外字段错误
+        """
+        if not data:
+            return
+        for alias in self._collect_aliases(model_cls):
+            data.pop(alias, None)
+
+    def _collect_aliases(self, model_cls: Type[BaseModel]) -> Set[str]:
+        alias_set: Set[str] = set()
+        populate_by_name = getattr(model_cls, "model_config", {}).get(
+            "populate_by_name", False
+        )
+        for name, info in model_cls.model_fields.items():
+            alias_set.update(self._field_aliases(name, info, populate_by_name))
+        return alias_set
+
+    @staticmethod
+    def _field_aliases(
+        name: str,
+        info,
+        populate_by_name: bool
+    ) -> Iterable[str]:
+        aliases: Set[str] = set()
+        if getattr(info, "alias", None):
+            aliases.add(info.alias)
+        validation_alias = getattr(info, "validation_alias", None)
+        if isinstance(validation_alias, str):
+            aliases.add(validation_alias)
+        elif isinstance(validation_alias, AliasChoices):
+            aliases.update(validation_alias.choices)
+        elif isinstance(validation_alias, AliasPath):
+            pass
+        if populate_by_name:
+            aliases.add(name)
+        return aliases
     
     
     
     
 @dataclass
 @dataclass