[DSIP-18454][Scheduler] Add schedule missed fire policy (#18464)
diff --git a/docs/docs/en/guide/upgrade/incompatible.md b/docs/docs/en/guide/upgrade/incompatible.md
index 0f60fcb..026d9b8 100644
--- a/docs/docs/en/guide/upgrade/incompatible.md
+++ b/docs/docs/en/guide/upgrade/incompatible.md
@@ -44,3 +44,7 @@
 
 * Remove import and export of workflow definition. ([#17940])(https://github.com/apache/dolphinscheduler/issues/17940)
 
+## 3.5.0
+
+* Add the `missed_fire_policy` column to `t_ds_schedules`. Existing schedules default to `FIRE_ALL_MISSED` to preserve the previous Quartz `IgnoreMisfires` behavior. ([#18464](https://github.com/apache/dolphinscheduler/pull/18464))
+
diff --git a/docs/docs/zh/guide/upgrade/incompatible.md b/docs/docs/zh/guide/upgrade/incompatible.md
index e6309be..db0ea2d 100644
--- a/docs/docs/zh/guide/upgrade/incompatible.md
+++ b/docs/docs/zh/guide/upgrade/incompatible.md
@@ -44,3 +44,7 @@
 
 * 移除导入导出工作流([#17940])(https://github.com/apache/dolphinscheduler/issues/17940)
 
+## 3.5.0
+
+* 为 `t_ds_schedules` 表新增 `missed_fire_policy` 字段。现有定时默认使用 `FIRE_ALL_MISSED`,以保持原有 Quartz `IgnoreMisfires` 行为。([#18464](https://github.com/apache/dolphinscheduler/pull/18464))
+
diff --git a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/dto/ScheduleParam.java b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/dto/ScheduleParam.java
index 88fd4ea..7d70c77 100644
--- a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/dto/ScheduleParam.java
+++ b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/dto/ScheduleParam.java
@@ -17,10 +17,14 @@
 
 package org.apache.dolphinscheduler.api.dto;
 
+import org.apache.dolphinscheduler.common.enums.ScheduleMissedFirePolicy;
+
 import java.util.Date;
 
 import lombok.Data;
 
+import com.fasterxml.jackson.annotation.JsonIgnore;
+
 /**
  * schedule parameters
  */
@@ -31,6 +35,10 @@
     private Date endTime;
     private String crontab;
     private String timezoneId;
+    private ScheduleMissedFirePolicy missedFirePolicy = ScheduleMissedFirePolicy.FIRE_ALL_MISSED;
+
+    @JsonIgnore
+    private boolean missedFirePolicySet;
 
     public ScheduleParam() {
     }
@@ -42,6 +50,15 @@
         this.crontab = crontab;
     }
 
+    public void setMissedFirePolicy(ScheduleMissedFirePolicy missedFirePolicy) {
+        this.missedFirePolicy = missedFirePolicy;
+        this.missedFirePolicySet = true;
+    }
+
+    public boolean isMissedFirePolicySet() {
+        return missedFirePolicySet;
+    }
+
     @Override
     public String toString() {
         return "ScheduleParam{"
diff --git a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/SchedulerServiceImpl.java b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/SchedulerServiceImpl.java
index 12df89e..7b0ae20 100644
--- a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/SchedulerServiceImpl.java
+++ b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/SchedulerServiceImpl.java
@@ -172,6 +172,8 @@
             throw new ServiceException(Status.REQUEST_PARAMS_NOT_VALID_ERROR, scheduleParam.getCrontab());
         }
         scheduleObj.setCrontab(scheduleParam.getCrontab());
+        validateMissedFirePolicy(scheduleParam);
+        scheduleObj.setMissedFirePolicy(scheduleParam.getMissedFirePolicy());
         scheduleObj.setTimezoneId(scheduleParam.getTimezoneId());
         scheduleObj.setWarningType(warningType);
         scheduleObj.setWarningGroupId(warningGroupId);
@@ -557,6 +559,10 @@
                 throw new ServiceException(Status.SCHEDULE_CRON_CHECK_FAILED, scheduleParam.getCrontab());
             }
             schedule.setCrontab(scheduleParam.getCrontab());
+            validateMissedFirePolicy(scheduleParam);
+            if (scheduleParam.isMissedFirePolicySet() && scheduleParam.getMissedFirePolicy() != null) {
+                schedule.setMissedFirePolicy(scheduleParam.getMissedFirePolicy());
+            }
             schedule.setTimezoneId(scheduleParam.getTimezoneId());
         }
 
@@ -585,4 +591,11 @@
         return schedule;
     }
 
+    private void validateMissedFirePolicy(ScheduleParam scheduleParam) {
+        if (scheduleParam.isMissedFirePolicySet() && scheduleParam.getMissedFirePolicy() == null) {
+            log.warn("Schedule missed fire policy is invalid.");
+            throw new ServiceException(Status.REQUEST_PARAMS_NOT_VALID_ERROR, "missedFirePolicy");
+        }
+    }
+
 }
diff --git a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/vo/ScheduleVO.java b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/vo/ScheduleVO.java
index fc4b1d9..8ddf9c3 100644
--- a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/vo/ScheduleVO.java
+++ b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/vo/ScheduleVO.java
@@ -20,6 +20,7 @@
 import org.apache.dolphinscheduler.common.enums.FailureStrategy;
 import org.apache.dolphinscheduler.common.enums.Priority;
 import org.apache.dolphinscheduler.common.enums.ReleaseState;
+import org.apache.dolphinscheduler.common.enums.ScheduleMissedFirePolicy;
 import org.apache.dolphinscheduler.common.enums.WarningType;
 import org.apache.dolphinscheduler.common.utils.DateUtils;
 import org.apache.dolphinscheduler.dao.entity.Schedule;
@@ -54,6 +55,8 @@
 
     private String crontab;
 
+    private ScheduleMissedFirePolicy missedFirePolicy;
+
     private FailureStrategy failureStrategy;
 
     private WarningType warningType;
@@ -83,6 +86,7 @@
     public ScheduleVO(Schedule schedule) {
         this.setId(schedule.getId());
         this.setCrontab(schedule.getCrontab());
+        this.setMissedFirePolicy(schedule.getMissedFirePolicy());
         this.setProjectName(schedule.getProjectName());
         this.setUserName(schedule.getUserName());
         this.setWorkerGroup(schedule.getWorkerGroup());
diff --git a/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/SchedulerServiceTest.java b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/SchedulerServiceTest.java
index 20ea9e3..3c9a9de 100644
--- a/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/SchedulerServiceTest.java
+++ b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/SchedulerServiceTest.java
@@ -17,10 +17,17 @@
 
 package org.apache.dolphinscheduler.api.service;
 
+import org.apache.dolphinscheduler.api.dto.ScheduleParam;
 import org.apache.dolphinscheduler.api.enums.Status;
 import org.apache.dolphinscheduler.api.exceptions.ServiceException;
 import org.apache.dolphinscheduler.api.service.impl.SchedulerServiceImpl;
+import org.apache.dolphinscheduler.api.validator.TenantExistValidator;
+import org.apache.dolphinscheduler.common.enums.FailureStrategy;
+import org.apache.dolphinscheduler.common.enums.Priority;
 import org.apache.dolphinscheduler.common.enums.ReleaseState;
+import org.apache.dolphinscheduler.common.enums.ScheduleMissedFirePolicy;
+import org.apache.dolphinscheduler.common.enums.WarningType;
+import org.apache.dolphinscheduler.common.utils.JSONUtils;
 import org.apache.dolphinscheduler.dao.entity.Project;
 import org.apache.dolphinscheduler.dao.entity.Schedule;
 import org.apache.dolphinscheduler.dao.entity.User;
@@ -28,6 +35,7 @@
 import org.apache.dolphinscheduler.dao.repository.ProjectDao;
 import org.apache.dolphinscheduler.dao.repository.ScheduleDao;
 import org.apache.dolphinscheduler.dao.repository.WorkflowDefinitionDao;
+import org.apache.dolphinscheduler.scheduler.api.SchedulerApi;
 
 import java.util.Optional;
 
@@ -35,6 +43,9 @@
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.EnumSource;
+import org.mockito.ArgumentCaptor;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
 import org.mockito.Mockito;
@@ -61,6 +72,15 @@
     @Mock
     private ProjectService projectService;
 
+    @Mock
+    private ExecutorService executorService;
+
+    @Mock
+    private TenantExistValidator tenantExistValidator;
+
+    @Mock
+    private SchedulerApi schedulerApi;
+
     protected static User user;
     protected Exception exception;
     private static final String userName = "userName";
@@ -81,6 +101,173 @@
     }
 
     @Test
+    public void testScheduleParamMissedFirePolicyPresence() {
+        String scheduleWithoutPolicy = "{\"startTime\":\"2019-12-16 00:00:00\","
+                + "\"endTime\":\"2019-12-17 00:00:00\",\"crontab\":\"0 0 6 * * ? *\"}";
+        String scheduleWithPolicy = "{\"startTime\":\"2019-12-16 00:00:00\","
+                + "\"endTime\":\"2019-12-17 00:00:00\",\"crontab\":\"0 0 6 * * ? *\","
+                + "\"missedFirePolicy\":\"SKIP_MISSED\"}";
+
+        ScheduleParam withoutPolicy = JSONUtils.parseObject(scheduleWithoutPolicy, ScheduleParam.class);
+        ScheduleParam withPolicy = JSONUtils.parseObject(scheduleWithPolicy, ScheduleParam.class);
+
+        Assertions.assertEquals(ScheduleMissedFirePolicy.FIRE_ALL_MISSED, withoutPolicy.getMissedFirePolicy());
+        Assertions.assertFalse(withoutPolicy.isMissedFirePolicySet());
+        Assertions.assertEquals(ScheduleMissedFirePolicy.SKIP_MISSED, withPolicy.getMissedFirePolicy());
+        Assertions.assertTrue(withPolicy.isMissedFirePolicySet());
+    }
+
+    @ParameterizedTest
+    @EnumSource(ScheduleMissedFirePolicy.class)
+    public void testInsertScheduleWithMissedFirePolicy(ScheduleMissedFirePolicy missedFirePolicy) {
+        Project project = this.getProject();
+        WorkflowDefinition workflowDefinition = this.getProcessDefinition();
+        Schedule insertedSchedule = new Schedule();
+        insertedSchedule.setId(scheduleId);
+        Mockito.when(projectDao.queryByCode(projectCode)).thenReturn(project);
+        Mockito.when(scheduleDao.queryByWorkflowDefinitionCode(processDefinitionCode)).thenReturn(null);
+        Mockito.when(workflowDefinitionDao.queryByCode(processDefinitionCode))
+                .thenReturn(Optional.of(workflowDefinition));
+        Mockito.when(scheduleDao.queryById(Mockito.any())).thenReturn(insertedSchedule);
+
+        Schedule result = schedulerService.insertSchedule(
+                user, projectCode, processDefinitionCode, scheduleExpression(missedFirePolicy), WarningType.NONE, 0,
+                FailureStrategy.CONTINUE, Priority.MEDIUM, "default", "tenantCode", environmentCode);
+
+        ArgumentCaptor<Schedule> scheduleCaptor = ArgumentCaptor.forClass(Schedule.class);
+        Mockito.verify(scheduleDao).insert(scheduleCaptor.capture());
+        Assertions.assertEquals(missedFirePolicy, scheduleCaptor.getValue().getMissedFirePolicy());
+        Assertions.assertSame(insertedSchedule, result);
+    }
+
+    @Test
+    public void testInsertScheduleDefaultsMissedFirePolicy() {
+        Mockito.when(projectDao.queryByCode(projectCode)).thenReturn(this.getProject());
+        Mockito.when(scheduleDao.queryByWorkflowDefinitionCode(processDefinitionCode)).thenReturn(null);
+        Mockito.when(workflowDefinitionDao.queryByCode(processDefinitionCode))
+                .thenReturn(Optional.of(this.getProcessDefinition()));
+        Mockito.when(scheduleDao.queryById(Mockito.anyInt())).thenReturn(new Schedule());
+
+        schedulerService.insertSchedule(
+                user, projectCode, processDefinitionCode, scheduleExpression(null), WarningType.NONE, 0,
+                FailureStrategy.CONTINUE, Priority.MEDIUM, "default", "tenantCode", environmentCode);
+
+        ArgumentCaptor<Schedule> scheduleCaptor = ArgumentCaptor.forClass(Schedule.class);
+        Mockito.verify(scheduleDao).insert(scheduleCaptor.capture());
+        Assertions.assertEquals(ScheduleMissedFirePolicy.FIRE_ALL_MISSED,
+                scheduleCaptor.getValue().getMissedFirePolicy());
+    }
+
+    @Test
+    public void testInsertScheduleRejectsExplicitNullMissedFirePolicy() {
+        assertInsertScheduleRejectsInvalidMissedFirePolicy("null");
+    }
+
+    @Test
+    public void testInsertScheduleRejectsUnknownMissedFirePolicy() {
+        assertInsertScheduleRejectsInvalidMissedFirePolicy("\"FIRE_ONCE_NWO\"");
+    }
+
+    @ParameterizedTest
+    @EnumSource(ScheduleMissedFirePolicy.class)
+    public void testUpdateScheduleWithMissedFirePolicy(ScheduleMissedFirePolicy missedFirePolicy) {
+        Schedule schedule = this.getSchedule();
+        schedule.setReleaseState(ReleaseState.OFFLINE);
+        WorkflowDefinition workflowDefinition = this.getProcessDefinition();
+        Mockito.when(projectDao.queryByCode(projectCode)).thenReturn(this.getProject());
+        Mockito.when(scheduleDao.queryById(scheduleId)).thenReturn(schedule);
+        Mockito.when(workflowDefinitionDao.queryByCode(processDefinitionCode))
+                .thenReturn(Optional.of(workflowDefinition));
+
+        schedulerService.updateSchedule(
+                user, projectCode, scheduleId, scheduleExpression(missedFirePolicy), WarningType.NONE, 0,
+                FailureStrategy.CONTINUE, Priority.MEDIUM, "default", "tenantCode", environmentCode);
+
+        Assertions.assertEquals(missedFirePolicy, schedule.getMissedFirePolicy());
+    }
+
+    @Test
+    public void testUpdateSchedulePreservesMissedFirePolicyWhenOmitted() {
+        Schedule schedule = this.getSchedule();
+        schedule.setReleaseState(ReleaseState.OFFLINE);
+        schedule.setMissedFirePolicy(ScheduleMissedFirePolicy.SKIP_MISSED);
+        WorkflowDefinition workflowDefinition = this.getProcessDefinition();
+        Mockito.when(projectDao.queryByCode(projectCode)).thenReturn(this.getProject());
+        Mockito.when(scheduleDao.queryById(scheduleId)).thenReturn(schedule);
+        Mockito.when(workflowDefinitionDao.queryByCode(processDefinitionCode))
+                .thenReturn(Optional.of(workflowDefinition));
+
+        schedulerService.updateSchedule(
+                user, projectCode, scheduleId, scheduleExpression(null), WarningType.NONE, 0,
+                FailureStrategy.CONTINUE, Priority.MEDIUM, "default", "tenantCode", environmentCode);
+
+        Assertions.assertEquals(ScheduleMissedFirePolicy.SKIP_MISSED, schedule.getMissedFirePolicy());
+    }
+
+    @Test
+    public void testUpdateScheduleRejectsExplicitNullMissedFirePolicy() {
+        assertUpdateScheduleRejectsInvalidMissedFirePolicy("null");
+    }
+
+    @Test
+    public void testUpdateScheduleRejectsUnknownMissedFirePolicy() {
+        assertUpdateScheduleRejectsInvalidMissedFirePolicy("\"FIRE_ONCE_NWO\"");
+    }
+
+    private void assertInsertScheduleRejectsInvalidMissedFirePolicy(String missedFirePolicyValue) {
+        Mockito.when(projectDao.queryByCode(projectCode)).thenReturn(this.getProject());
+        Mockito.when(scheduleDao.queryByWorkflowDefinitionCode(processDefinitionCode)).thenReturn(null);
+        Mockito.when(workflowDefinitionDao.queryByCode(processDefinitionCode))
+                .thenReturn(Optional.of(this.getProcessDefinition()));
+
+        exception = Assertions.assertThrows(ServiceException.class,
+                () -> schedulerService.insertSchedule(
+                        user, projectCode, processDefinitionCode,
+                        scheduleExpressionWithPolicyValue(missedFirePolicyValue),
+                        WarningType.NONE, 0, FailureStrategy.CONTINUE, Priority.MEDIUM, "default", "tenantCode",
+                        environmentCode));
+
+        Assertions.assertEquals(Status.REQUEST_PARAMS_NOT_VALID_ERROR.getCode(),
+                ((ServiceException) exception).getCode());
+        Mockito.verify(scheduleDao, Mockito.never()).insert(Mockito.any());
+    }
+
+    private void assertUpdateScheduleRejectsInvalidMissedFirePolicy(String missedFirePolicyValue) {
+        Schedule schedule = this.getSchedule();
+        schedule.setReleaseState(ReleaseState.OFFLINE);
+        schedule.setMissedFirePolicy(ScheduleMissedFirePolicy.SKIP_MISSED);
+        Mockito.when(projectDao.queryByCode(projectCode)).thenReturn(this.getProject());
+        Mockito.when(scheduleDao.queryById(scheduleId)).thenReturn(schedule);
+        Mockito.when(workflowDefinitionDao.queryByCode(processDefinitionCode))
+                .thenReturn(Optional.of(this.getProcessDefinition()));
+
+        exception = Assertions.assertThrows(ServiceException.class,
+                () -> schedulerService.updateSchedule(
+                        user, projectCode, scheduleId, scheduleExpressionWithPolicyValue(missedFirePolicyValue),
+                        WarningType.NONE, 0, FailureStrategy.CONTINUE, Priority.MEDIUM, "default", "tenantCode",
+                        environmentCode));
+
+        Assertions.assertEquals(Status.REQUEST_PARAMS_NOT_VALID_ERROR.getCode(),
+                ((ServiceException) exception).getCode());
+        Assertions.assertEquals(ScheduleMissedFirePolicy.SKIP_MISSED, schedule.getMissedFirePolicy());
+        Mockito.verify(scheduleDao, Mockito.never()).updateById(Mockito.any());
+    }
+
+    private String scheduleExpression(ScheduleMissedFirePolicy missedFirePolicy) {
+        String policy = missedFirePolicy == null ? "" : ",\"missedFirePolicy\":\"" + missedFirePolicy.name() + "\"";
+        return scheduleExpressionWithPolicy(policy);
+    }
+
+    private String scheduleExpressionWithPolicyValue(String missedFirePolicyValue) {
+        return scheduleExpressionWithPolicy(",\"missedFirePolicy\":" + missedFirePolicyValue);
+    }
+
+    private String scheduleExpressionWithPolicy(String policy) {
+        return "{\"startTime\":\"2019-12-16 00:00:00\",\"endTime\":\"2019-12-17 00:00:00\","
+                + "\"crontab\":\"0 0 6 * * ? *\",\"timezoneId\":\"Asia/Shanghai\"" + policy + "}";
+    }
+
+    @Test
     public void testDeleteSchedules() {
         Schedule schedule = this.getSchedule();
 
diff --git a/dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/enums/ScheduleMissedFirePolicy.java b/dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/enums/ScheduleMissedFirePolicy.java
new file mode 100644
index 0000000..7959d63
--- /dev/null
+++ b/dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/enums/ScheduleMissedFirePolicy.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dolphinscheduler.common.enums;
+
+import lombok.Getter;
+
+import com.baomidou.mybatisplus.annotation.EnumValue;
+
+@Getter
+public enum ScheduleMissedFirePolicy {
+
+    SKIP_MISSED(0),
+    FIRE_ONCE_NOW(1),
+    FIRE_ALL_MISSED(2);
+
+    @EnumValue
+    private final int code;
+
+    ScheduleMissedFirePolicy(int code) {
+        this.code = code;
+    }
+}
diff --git a/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/entity/Schedule.java b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/entity/Schedule.java
index a55c8d1..965a5c9 100644
--- a/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/entity/Schedule.java
+++ b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/entity/Schedule.java
@@ -20,6 +20,7 @@
 import org.apache.dolphinscheduler.common.enums.FailureStrategy;
 import org.apache.dolphinscheduler.common.enums.Priority;
 import org.apache.dolphinscheduler.common.enums.ReleaseState;
+import org.apache.dolphinscheduler.common.enums.ScheduleMissedFirePolicy;
 import org.apache.dolphinscheduler.common.enums.WarningType;
 
 import java.util.Date;
@@ -67,6 +68,8 @@
 
     private String crontab;
 
+    private ScheduleMissedFirePolicy missedFirePolicy;
+
     private FailureStrategy failureStrategy;
 
     private WarningType warningType;
diff --git a/dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/ScheduleMapper.xml b/dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/ScheduleMapper.xml
index 99c1a59..78a401c 100644
--- a/dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/ScheduleMapper.xml
+++ b/dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/ScheduleMapper.xml
@@ -19,12 +19,12 @@
 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
 <mapper namespace="org.apache.dolphinscheduler.dao.mapper.ScheduleMapper">
     <sql id="baseSql">
-        id, workflow_definition_code, start_time, end_time, timezone_id, crontab, failure_strategy, user_id, release_state,
+        id, workflow_definition_code, start_time, end_time, timezone_id, crontab, missed_fire_policy, failure_strategy, user_id, release_state,
         warning_type, warning_group_id, workflow_instance_priority, worker_group, tenant_code, environment_code, create_time, update_time
     </sql>
     <sql id="baseSqlV2">
         ${alias}.id, ${alias}.workflow_definition_code, ${alias}.start_time, ${alias}.end_time, ${alias}.timezone_id,
-        ${alias}.crontab, ${alias}.failure_strategy, ${alias}.user_id, ${alias}.release_state, ${alias}.warning_type,
+        ${alias}.crontab, ${alias}.missed_fire_policy, ${alias}.failure_strategy, ${alias}.user_id, ${alias}.release_state, ${alias}.warning_type,
         ${alias}.warning_group_id, ${alias}.workflow_instance_priority, ${alias}.worker_group, ${alias}.tenant_code, ${alias}.environment_code, ${alias}.create_time,
         ${alias}.update_time
     </sql>
diff --git a/dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_h2.sql b/dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_h2.sql
index 1725b5c..d69728b 100644
--- a/dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_h2.sql
+++ b/dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_h2.sql
@@ -858,6 +858,7 @@
     end_time                  datetime     NOT NULL,
     timezone_id               varchar(40) DEFAULT NULL,
     crontab                   varchar(255) NOT NULL,
+    missed_fire_policy        tinyint NOT NULL DEFAULT 2,
     failure_strategy          tinyint(4) NOT NULL,
     user_id                   int(11) NOT NULL,
     release_state             tinyint(4) NOT NULL,
diff --git a/dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_mysql.sql b/dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_mysql.sql
index f6dfa61..361cdc3 100644
--- a/dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_mysql.sql
+++ b/dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_mysql.sql
@@ -859,6 +859,7 @@
   `end_time` datetime NOT NULL COMMENT 'end time',
   `timezone_id` varchar(40) DEFAULT NULL COMMENT 'schedule timezone id',
   `crontab` varchar(255) NOT NULL COMMENT 'crontab description',
+  `missed_fire_policy` tinyint NOT NULL DEFAULT '2' COMMENT 'missed fire policy: 0 skip missed, 1 fire once now, 2 fire all missed',
   `failure_strategy` tinyint(4) NOT NULL COMMENT 'failure strategy. 0:end,1:continue',
   `user_id` int(11) NOT NULL COMMENT 'user id',
   `release_state` tinyint(4) NOT NULL COMMENT 'release state. 0:offline,1:online ',
diff --git a/dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_postgresql.sql b/dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_postgresql.sql
index 698b357..3877162 100644
--- a/dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_postgresql.sql
+++ b/dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_postgresql.sql
@@ -785,6 +785,7 @@
   end_time timestamp NOT NULL ,
   timezone_id varchar(40) default NULL ,
   crontab varchar(255) NOT NULL ,
+  missed_fire_policy smallint NOT NULL DEFAULT 2,
   failure_strategy int NOT NULL ,
   user_id int NOT NULL ,
   release_state int NOT NULL ,
diff --git a/dolphinscheduler-dao/src/main/resources/sql/upgrade/3.5.0_schema/mysql/dolphinscheduler_ddl.sql b/dolphinscheduler-dao/src/main/resources/sql/upgrade/3.5.0_schema/mysql/dolphinscheduler_ddl.sql
index 3f7d317..afeb991 100644
--- a/dolphinscheduler-dao/src/main/resources/sql/upgrade/3.5.0_schema/mysql/dolphinscheduler_ddl.sql
+++ b/dolphinscheduler-dao/src/main/resources/sql/upgrade/3.5.0_schema/mysql/dolphinscheduler_ddl.sql
@@ -17,4 +17,6 @@
 
 ALTER TABLE `t_ds_task_instance` ADD INDEX idx_project_submit_time (project_code ASC, submit_time DESC);
 ALTER TABLE `t_ds_workflow_instance` ADD INDEX idx_project_start_time (project_code ASC, start_time DESC);
+ALTER TABLE `t_ds_schedules`
+    ADD COLUMN `missed_fire_policy` tinyint NOT NULL DEFAULT '2' COMMENT 'missed fire policy: 0 skip missed, 1 fire once now, 2 fire all missed' AFTER `crontab`;
 
diff --git a/dolphinscheduler-dao/src/main/resources/sql/upgrade/3.5.0_schema/postgresql/dolphinscheduler_ddl.sql b/dolphinscheduler-dao/src/main/resources/sql/upgrade/3.5.0_schema/postgresql/dolphinscheduler_ddl.sql
index 61a5ae8..1709fe5 100644
--- a/dolphinscheduler-dao/src/main/resources/sql/upgrade/3.5.0_schema/postgresql/dolphinscheduler_ddl.sql
+++ b/dolphinscheduler-dao/src/main/resources/sql/upgrade/3.5.0_schema/postgresql/dolphinscheduler_ddl.sql
@@ -17,3 +17,5 @@
 
 CREATE INDEX idx_project_submit_time ON t_ds_task_instance (project_code ASC, submit_time DESC);
 CREATE INDEX idx_project_start_time ON t_ds_workflow_instance (project_code ASC, start_time DESC);
+ALTER TABLE t_ds_schedules
+    ADD COLUMN missed_fire_policy smallint NOT NULL DEFAULT 2;
diff --git a/dolphinscheduler-scheduler-plugin/dolphinscheduler-scheduler-quartz/src/main/java/org/apache/dolphinscheduler/scheduler/quartz/CronScheduleBuilderFactory.java b/dolphinscheduler-scheduler-plugin/dolphinscheduler-scheduler-quartz/src/main/java/org/apache/dolphinscheduler/scheduler/quartz/CronScheduleBuilderFactory.java
new file mode 100644
index 0000000..4702995
--- /dev/null
+++ b/dolphinscheduler-scheduler-plugin/dolphinscheduler-scheduler-quartz/src/main/java/org/apache/dolphinscheduler/scheduler/quartz/CronScheduleBuilderFactory.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dolphinscheduler.scheduler.quartz;
+
+import org.apache.dolphinscheduler.common.enums.ScheduleMissedFirePolicy;
+import org.apache.dolphinscheduler.dao.entity.Schedule;
+
+import org.quartz.CronScheduleBuilder;
+
+interface CronScheduleBuilderFactory {
+
+    CronScheduleBuilder createCronScheduleBuilder(Schedule schedule);
+
+    static CronScheduleBuilderFactory getFactory(ScheduleMissedFirePolicy missedFirePolicy) {
+        ScheduleMissedFirePolicy effectivePolicy = missedFirePolicy == null
+                ? ScheduleMissedFirePolicy.FIRE_ALL_MISSED
+                : missedFirePolicy;
+        switch (effectivePolicy) {
+            case SKIP_MISSED:
+                return new SkipMissedCronScheduleBuilderFactory();
+            case FIRE_ONCE_NOW:
+                return new FireOnceNowCronScheduleBuilderFactory();
+            case FIRE_ALL_MISSED:
+                return new FireAllMissedCronScheduleBuilderFactory();
+            default:
+                throw new IllegalArgumentException("Unsupported schedule missed fire policy: " + missedFirePolicy);
+        }
+    }
+}
diff --git a/dolphinscheduler-scheduler-plugin/dolphinscheduler-scheduler-quartz/src/main/java/org/apache/dolphinscheduler/scheduler/quartz/FireAllMissedCronScheduleBuilderFactory.java b/dolphinscheduler-scheduler-plugin/dolphinscheduler-scheduler-quartz/src/main/java/org/apache/dolphinscheduler/scheduler/quartz/FireAllMissedCronScheduleBuilderFactory.java
new file mode 100644
index 0000000..b3022d1
--- /dev/null
+++ b/dolphinscheduler-scheduler-plugin/dolphinscheduler-scheduler-quartz/src/main/java/org/apache/dolphinscheduler/scheduler/quartz/FireAllMissedCronScheduleBuilderFactory.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dolphinscheduler.scheduler.quartz;
+
+import org.apache.dolphinscheduler.common.utils.DateUtils;
+import org.apache.dolphinscheduler.dao.entity.Schedule;
+
+import org.quartz.CronScheduleBuilder;
+
+final class FireAllMissedCronScheduleBuilderFactory implements CronScheduleBuilderFactory {
+
+    @Override
+    public CronScheduleBuilder createCronScheduleBuilder(Schedule schedule) {
+        return CronScheduleBuilder.cronSchedule(schedule.getCrontab())
+                .withMisfireHandlingInstructionIgnoreMisfires()
+                .inTimeZone(DateUtils.getTimezone(schedule.getTimezoneId()));
+    }
+}
diff --git a/dolphinscheduler-scheduler-plugin/dolphinscheduler-scheduler-quartz/src/main/java/org/apache/dolphinscheduler/scheduler/quartz/FireOnceNowCronScheduleBuilderFactory.java b/dolphinscheduler-scheduler-plugin/dolphinscheduler-scheduler-quartz/src/main/java/org/apache/dolphinscheduler/scheduler/quartz/FireOnceNowCronScheduleBuilderFactory.java
new file mode 100644
index 0000000..9990f42
--- /dev/null
+++ b/dolphinscheduler-scheduler-plugin/dolphinscheduler-scheduler-quartz/src/main/java/org/apache/dolphinscheduler/scheduler/quartz/FireOnceNowCronScheduleBuilderFactory.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dolphinscheduler.scheduler.quartz;
+
+import org.apache.dolphinscheduler.common.utils.DateUtils;
+import org.apache.dolphinscheduler.dao.entity.Schedule;
+
+import org.quartz.CronScheduleBuilder;
+
+final class FireOnceNowCronScheduleBuilderFactory implements CronScheduleBuilderFactory {
+
+    @Override
+    public CronScheduleBuilder createCronScheduleBuilder(Schedule schedule) {
+        return CronScheduleBuilder.cronSchedule(schedule.getCrontab())
+                .withMisfireHandlingInstructionFireAndProceed()
+                .inTimeZone(DateUtils.getTimezone(schedule.getTimezoneId()));
+    }
+}
diff --git a/dolphinscheduler-scheduler-plugin/dolphinscheduler-scheduler-quartz/src/main/java/org/apache/dolphinscheduler/scheduler/quartz/QuartzCornTriggerBuilder.java b/dolphinscheduler-scheduler-plugin/dolphinscheduler-scheduler-quartz/src/main/java/org/apache/dolphinscheduler/scheduler/quartz/QuartzCornTriggerBuilder.java
index b7177e7..270f06e 100644
--- a/dolphinscheduler-scheduler-plugin/dolphinscheduler-scheduler-quartz/src/main/java/org/apache/dolphinscheduler/scheduler/quartz/QuartzCornTriggerBuilder.java
+++ b/dolphinscheduler-scheduler-plugin/dolphinscheduler-scheduler-quartz/src/main/java/org/apache/dolphinscheduler/scheduler/quartz/QuartzCornTriggerBuilder.java
@@ -81,14 +81,14 @@
         JobKey jobKey = QuartzJobKey.of(projectId, schedule.getId()).toJobKey();
 
         TriggerKey triggerKey = TriggerKey.triggerKey(jobKey.getName(), jobKey.getGroup());
+        CronScheduleBuilder scheduleBuilder = CronScheduleBuilderFactory.getFactory(schedule.getMissedFirePolicy())
+                .createCronScheduleBuilder(schedule);
+
         return TriggerBuilder.newTrigger()
                 .withIdentity(triggerKey)
                 .startAt(startDate)
                 .endAt(endDate)
-                .withSchedule(
-                        CronScheduleBuilder.cronSchedule(schedule.getCrontab())
-                                .withMisfireHandlingInstructionIgnoreMisfires()
-                                .inTimeZone(DateUtils.getTimezone(schedule.getTimezoneId())))
+                .withSchedule(scheduleBuilder)
                 .build();
     }
 
diff --git a/dolphinscheduler-scheduler-plugin/dolphinscheduler-scheduler-quartz/src/main/java/org/apache/dolphinscheduler/scheduler/quartz/SkipMissedCronScheduleBuilderFactory.java b/dolphinscheduler-scheduler-plugin/dolphinscheduler-scheduler-quartz/src/main/java/org/apache/dolphinscheduler/scheduler/quartz/SkipMissedCronScheduleBuilderFactory.java
new file mode 100644
index 0000000..2d94808
--- /dev/null
+++ b/dolphinscheduler-scheduler-plugin/dolphinscheduler-scheduler-quartz/src/main/java/org/apache/dolphinscheduler/scheduler/quartz/SkipMissedCronScheduleBuilderFactory.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dolphinscheduler.scheduler.quartz;
+
+import org.apache.dolphinscheduler.common.utils.DateUtils;
+import org.apache.dolphinscheduler.dao.entity.Schedule;
+
+import org.quartz.CronScheduleBuilder;
+
+final class SkipMissedCronScheduleBuilderFactory implements CronScheduleBuilderFactory {
+
+    @Override
+    public CronScheduleBuilder createCronScheduleBuilder(Schedule schedule) {
+        return CronScheduleBuilder.cronSchedule(schedule.getCrontab())
+                .withMisfireHandlingInstructionDoNothing()
+                .inTimeZone(DateUtils.getTimezone(schedule.getTimezoneId()));
+    }
+}
diff --git a/dolphinscheduler-scheduler-plugin/dolphinscheduler-scheduler-quartz/src/test/java/org/apache/dolphinscheduler/scheduler/quartz/CronScheduleBuilderFactoryTest.java b/dolphinscheduler-scheduler-plugin/dolphinscheduler-scheduler-quartz/src/test/java/org/apache/dolphinscheduler/scheduler/quartz/CronScheduleBuilderFactoryTest.java
new file mode 100644
index 0000000..f006472
--- /dev/null
+++ b/dolphinscheduler-scheduler-plugin/dolphinscheduler-scheduler-quartz/src/test/java/org/apache/dolphinscheduler/scheduler/quartz/CronScheduleBuilderFactoryTest.java
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dolphinscheduler.scheduler.quartz;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+
+import org.apache.dolphinscheduler.common.enums.ScheduleMissedFirePolicy;
+import org.apache.dolphinscheduler.dao.entity.Schedule;
+
+import org.junit.jupiter.api.Test;
+import org.quartz.CronTrigger;
+import org.quartz.Trigger;
+
+class CronScheduleBuilderFactoryTest {
+
+    private static final String CRON_EXPRESSION = "0 0 * * * ?";
+
+    private static final String TIMEZONE_ID = "Asia/Shanghai";
+
+    @Test
+    void shouldCreateSkipMissedCronScheduleBuilder() {
+        assertFactoryAndMisfireInstruction(
+                ScheduleMissedFirePolicy.SKIP_MISSED,
+                SkipMissedCronScheduleBuilderFactory.class,
+                CronTrigger.MISFIRE_INSTRUCTION_DO_NOTHING);
+    }
+
+    @Test
+    void shouldCreateFireOnceNowCronScheduleBuilder() {
+        assertFactoryAndMisfireInstruction(
+                ScheduleMissedFirePolicy.FIRE_ONCE_NOW,
+                FireOnceNowCronScheduleBuilderFactory.class,
+                CronTrigger.MISFIRE_INSTRUCTION_FIRE_ONCE_NOW);
+    }
+
+    @Test
+    void shouldCreateFireAllMissedCronScheduleBuilder() {
+        assertFactoryAndMisfireInstruction(
+                ScheduleMissedFirePolicy.FIRE_ALL_MISSED,
+                FireAllMissedCronScheduleBuilderFactory.class,
+                Trigger.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY);
+    }
+
+    @Test
+    void shouldCreateFireAllMissedCronScheduleBuilderByDefault() {
+        assertFactoryAndMisfireInstruction(
+                null,
+                FireAllMissedCronScheduleBuilderFactory.class,
+                Trigger.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY);
+    }
+
+    private void assertFactoryAndMisfireInstruction(
+                                                    ScheduleMissedFirePolicy policy,
+                                                    Class<? extends CronScheduleBuilderFactory> expectedFactoryClass,
+                                                    int expectedMisfireInstruction) {
+        Schedule schedule = new Schedule();
+        schedule.setCrontab(CRON_EXPRESSION);
+        schedule.setTimezoneId(TIMEZONE_ID);
+        CronScheduleBuilderFactory factory = CronScheduleBuilderFactory.getFactory(policy);
+        assertInstanceOf(expectedFactoryClass, factory);
+        Trigger trigger = factory.createCronScheduleBuilder(schedule).build();
+        CronTrigger cronTrigger = assertInstanceOf(CronTrigger.class, trigger);
+        assertEquals(expectedMisfireInstruction, cronTrigger.getMisfireInstruction());
+        assertEquals(TIMEZONE_ID, cronTrigger.getTimeZone().getID());
+    }
+}
diff --git a/dolphinscheduler-ui/src/locales/en_US/project.ts b/dolphinscheduler-ui/src/locales/en_US/project.ts
index 40e553d..534c119 100644
--- a/dolphinscheduler-ui/src/locales/en_US/project.ts
+++ b/dolphinscheduler-ui/src/locales/en_US/project.ts
@@ -149,6 +149,10 @@
     start_time: 'Start Time',
     end_time: 'End Time',
     crontab: 'Crontab',
+    missed_fire_policy: 'Missed Fire Policy',
+    skip_missed: 'Skip missed executions',
+    fire_once_now: 'Fire once immediately',
+    fire_all_missed: 'Fire all missed executions',
     delete_confirm: 'Delete?',
     delete_confirm_with_name: 'Delete "{name}"?',
     delete_irreversible:
diff --git a/dolphinscheduler-ui/src/locales/zh_CN/project.ts b/dolphinscheduler-ui/src/locales/zh_CN/project.ts
index abaa84a..429fd49 100644
--- a/dolphinscheduler-ui/src/locales/zh_CN/project.ts
+++ b/dolphinscheduler-ui/src/locales/zh_CN/project.ts
@@ -148,6 +148,10 @@
     start_time: '开始时间',
     end_time: '结束时间',
     crontab: 'Crontab',
+    missed_fire_policy: '定时错过策略',
+    skip_missed: '跳过错过的执行,等待下一次调度',
+    fire_once_now: '立即补触发一次,之后按正常节奏继续调度',
+    fire_all_missed: '补触发所有错过的执行,之后按正常节奏继续调度',
     delete_confirm: '确定删除吗?',
     delete_confirm_with_name: '确定删除“{name}”吗?',
     delete_irreversible: '此操作不可撤销。工作流及其关联数据将被永久删除。',
diff --git a/dolphinscheduler-ui/src/views/projects/workflow/definition/components/timing-modal.tsx b/dolphinscheduler-ui/src/views/projects/workflow/definition/components/timing-modal.tsx
index c302305..5d15f06 100644
--- a/dolphinscheduler-ui/src/views/projects/workflow/definition/components/timing-modal.tsx
+++ b/dolphinscheduler-ui/src/views/projects/workflow/definition/components/timing-modal.tsx
@@ -295,6 +295,8 @@
         ]
         timingState.timingForm.crontab = props.row.crontab
         timingState.timingForm.timezoneId = props.row.timezoneId
+        timingState.timingForm.missedFirePolicy =
+          props.row.missedFirePolicy || 'FIRE_ALL_MISSED'
         timingState.timingForm.failureStrategy = props.row.failureStrategy
         timingState.timingForm.warningType = props.row.warningType
         timingState.timingForm.workflowInstancePriority =
@@ -411,6 +413,28 @@
             </NList>
           </NFormItem>
           <NFormItem
+            label={t('project.workflow.missed_fire_policy')}
+            path='missedFirePolicy'
+          >
+            <NSelect
+              options={[
+                {
+                  value: 'SKIP_MISSED',
+                  label: t('project.workflow.skip_missed')
+                },
+                {
+                  value: 'FIRE_ONCE_NOW',
+                  label: t('project.workflow.fire_once_now')
+                },
+                {
+                  value: 'FIRE_ALL_MISSED',
+                  label: t('project.workflow.fire_all_missed')
+                }
+              ]}
+              v-model:value={this.timingForm.missedFirePolicy}
+            />
+          </NFormItem>
+          <NFormItem
             label={t('project.workflow.failure_strategy')}
             path='failureStrategy'
           >
diff --git a/dolphinscheduler-ui/src/views/projects/workflow/definition/components/use-form.ts b/dolphinscheduler-ui/src/views/projects/workflow/definition/components/use-form.ts
index f4955a9..9329c25 100644
--- a/dolphinscheduler-ui/src/views/projects/workflow/definition/components/use-form.ts
+++ b/dolphinscheduler-ui/src/views/projects/workflow/definition/components/use-form.ts
@@ -136,6 +136,7 @@
       ],
       crontab: '0 0 * * * ? *',
       timezoneId: Intl.DateTimeFormat().resolvedOptions().timeZone,
+      missedFirePolicy: 'FIRE_ALL_MISSED',
       failureStrategy: 'CONTINUE',
       warningType: 'NONE',
       workflowInstancePriority: 'MEDIUM',
diff --git a/dolphinscheduler-ui/src/views/projects/workflow/definition/components/use-modal.ts b/dolphinscheduler-ui/src/views/projects/workflow/definition/components/use-modal.ts
index 4baac0f..203ae5b 100644
--- a/dolphinscheduler-ui/src/views/projects/workflow/definition/components/use-modal.ts
+++ b/dolphinscheduler-ui/src/views/projects/workflow/definition/components/use-modal.ts
@@ -180,7 +180,8 @@
         startTime: start,
         endTime: end,
         crontab: state.timingForm.crontab,
-        timezoneId: state.timingForm.timezoneId
+        timezoneId: state.timingForm.timezoneId,
+        missedFirePolicy: state.timingForm.missedFirePolicy
       }),
       failureStrategy: state.timingForm.failureStrategy,
       warningType: state.timingForm.warningType,