diff --git a/pom.xml b/pom.xml
index 07656aaba1d6cb877d02460c4f17787abc044142..8479c2723f023d6cd17100ab20aca5efe8d085e7 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
 	<modelVersion>4.0.0</modelVersion>
 	<groupId>org.codelibs.fess</groupId>
 	<artifactId>fess</artifactId>
@@ -40,8 +41,9 @@
 
 		<!-- Main Framework -->
 		<dbflute.version>1.1.1</dbflute.version>
-		<lastaflute.version>0.7.8-RC2</lastaflute.version>
+		<lastaflute.version>0.7.9-RC2</lastaflute.version>
 		<lasta.taglib.version>0.6.8</lasta.taglib.version>
+		<lasta.job.version>0.2.0-RCB</lasta.job.version>
 		<servlet.version>3.1.0</servlet.version>
 		<jsp.version>2.3.1</jsp.version>
 		<mailflute.version>0.4.8</mailflute.version>
@@ -58,7 +60,7 @@
 		<utflute.version>0.6.0E</utflute.version>
 
 		<!-- Crawler -->
-		<crawler.version>1.0.2</crawler.version>
+		<crawler.version>1.0.3-SNAPSHOT</crawler.version>
 
 		<!-- Suggest -->
 		<suggest.version>2.1.1</suggest.version>
@@ -75,7 +77,7 @@
 		<packaging.fess.app.dir>${packaging.fess.home.dir}/app</packaging.fess.app.dir>
 		<packaging.fess.bin.dir>${packaging.fess.home.dir}/bin</packaging.fess.bin.dir>
 		<packaging.fess.conf.dir>/etc/fess</packaging.fess.conf.dir>
-        <packaging.fess.var.dir>/var/lib/fess</packaging.fess.var.dir>
+		<packaging.fess.var.dir>/var/lib/fess</packaging.fess.var.dir>
 		<packaging.fess.lib.dir>${packaging.fess.home.dir}/lib</packaging.fess.lib.dir>
 		<packaging.fess.log.dir>/var/log/fess</packaging.fess.log.dir>
 		<packaging.fess.temp.dir>/var/tmp/fess</packaging.fess.temp.dir>
@@ -95,7 +97,7 @@
 			</resource>
 		</resources>
 
-		<!-- This file contains all the common properties used to build the different
+		<!-- This file contains all the common properties used to build the different 
 			packages (tar.gz, deb, rpm) using Maven resources plugin -->
 		<filters>
 			<filter>src/packaging/common/packaging.properties</filter>
@@ -759,9 +761,9 @@
 
 		<!-- scheduler -->
 		<dependency>
-			<groupId>org.quartz-scheduler</groupId>
-			<artifactId>quartz</artifactId>
-			<version>2.2.2</version>
+			<groupId>org.lastaflute.job</groupId>
+			<artifactId>lasta-job</artifactId>
+			<version>${lasta.job.version}</version>
 		</dependency>
 
 		<!-- mail -->
diff --git a/src/main/java/org/codelibs/fess/Constants.java b/src/main/java/org/codelibs/fess/Constants.java
index 920d98094e26d97a8d90606183d24ff15e9f56fb..b2b4266e7b03a255def935449a89964215751fe3 100644
--- a/src/main/java/org/codelibs/fess/Constants.java
+++ b/src/main/java/org/codelibs/fess/Constants.java
@@ -56,6 +56,8 @@ public class Constants extends CoreLibConstants {
 
     public static final String FAIL = "fail";
 
+    public static final String STOP = "stop";
+
     public static final String ITEM_LABEL = "label";
 
     public static final String ITEM_VALUE = "value";
@@ -66,13 +68,13 @@ public class Constants extends CoreLibConstants {
 
     public static final String MS932 = "MS932";
 
-    public static final String DEFAULT_CRON_EXPRESSION = "0 0 0 * * ?";
+    public static final String DEFAULT_CRON_EXPRESSION = "0 0 * * *";
 
-    public static final String DEFAULT_SEARCH_LOG_CRON_EXPRESSION = "0 * * * * ?";
+    public static final String DEFAULT_SEARCH_LOG_CRON_EXPRESSION = "* * * * *";
 
-    public static final String DEFAULT_DAILY_CRON_EXPRESSION = "0 0 0 * * ?";
+    public static final String DEFAULT_DAILY_CRON_EXPRESSION = "0 0 * * *";
 
-    public static final String DEFAULT_HOURLY_CRON_EXPRESSION = "0 0 * * * ?";
+    public static final String DEFAULT_HOURLY_CRON_EXPRESSION = "0 * * * *";
 
     public static final int DEFAULT_INTERVAL_TIME_FOR_FS = 1000;
 
@@ -279,12 +281,9 @@ public class Constants extends CoreLibConstants {
     public static final String OPTION_QUERY_NQ = "nq";
 
     // job
-    public static final String JOB_ID_PREFIX = "job";
 
     public static final String SCHEDULED_JOB = "scheduledJob";
 
-    public static final String JOB_EXECUTOR_TYPE = "jobExecutor";
-
     public static final String DEFAULT_JOB_TARGET = "all";
 
     public static final String DEFAULT_JOB_SCRIPT_TYPE = "groovy";
diff --git a/src/main/java/org/codelibs/fess/app/job/AllJobScheduler.java b/src/main/java/org/codelibs/fess/app/job/AllJobScheduler.java
new file mode 100644
index 0000000000000000000000000000000000000000..edb7424089169151270d6d89a10c4a767e41c832
--- /dev/null
+++ b/src/main/java/org/codelibs/fess/app/job/AllJobScheduler.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2012-2016 CodeLibs Project and the Others.
+ *
+ * Licensed 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.codelibs.fess.app.job;
+
+import javax.annotation.Resource;
+
+import org.codelibs.core.lang.StringUtil;
+import org.codelibs.fess.Constants;
+import org.codelibs.fess.app.logic.AccessContextLogic;
+import org.codelibs.fess.app.service.ScheduledJobService;
+import org.codelibs.fess.es.config.exbhv.JobLogBhv;
+import org.codelibs.fess.helper.SystemHelper;
+import org.codelibs.fess.mylasta.direction.FessConfig;
+import org.codelibs.fess.util.ComponentUtil;
+import org.dbflute.optional.OptionalThing;
+import org.lastaflute.core.time.TimeManager;
+import org.lastaflute.di.core.exception.TooManyRegistrationComponentException;
+import org.lastaflute.di.core.smart.hot.HotdeployUtil;
+import org.lastaflute.job.LaCron;
+import org.lastaflute.job.LaJob;
+import org.lastaflute.job.LaJobRunner;
+import org.lastaflute.job.LaJobRuntime;
+import org.lastaflute.job.LaJobScheduler;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class AllJobScheduler implements LaJobScheduler {
+    private static final Logger logger = LoggerFactory.getLogger(AllJobScheduler.class);
+
+    protected static final String APP_TYPE = "JOB";
+
+    @Resource
+    private TimeManager timeManager;
+
+    @Resource
+    private FessConfig fessConfig;
+
+    @Resource
+    private AccessContextLogic accessContextLogic;
+
+    @Resource
+    private ScheduledJobService scheduledJobService;
+
+    @Resource
+    private SystemHelper systemHelper;
+
+    protected Class<? extends LaJob> jobClass = ScriptExecutorJob.class;
+
+    @Override
+    public void schedule(LaCron cron) {
+        scheduledJobService.start(cron);
+
+        final String myName = fessConfig.getSchedulerTargetName();
+        if (StringUtil.isNotBlank(myName)) {
+            ComponentUtil.getComponent(JobLogBhv.class).queryDelete(cb -> {
+                cb.query().setJobStatus_Equal(Constants.RUNNING);
+                cb.query().setTarget_Equal(myName);
+            });
+        }
+
+    }
+
+    @Override
+    public LaJobRunner createRunner() {
+        return new LaJobRunner() {
+            @Override
+            protected boolean isSuppressHotdeploy() { // TODO workaround
+                return true;
+            }
+
+            @Override
+            protected void actuallyRun(Class<? extends LaJob> jobType, LaJobRuntime runtime) { // TODO workaround
+                try {
+                    super.actuallyRun(jobType, runtime);
+                } catch (TooManyRegistrationComponentException e) {
+                    if (HotdeployUtil.isHotdeploy()) {
+                        logger.warn("Failed to start job {}", jobType);
+                    } else {
+                        throw e;
+                    }
+                }
+            }
+        }.useAccessContext(resource -> {
+            return accessContextLogic.create(resource, () -> OptionalThing.empty(), () -> OptionalThing.empty(), () -> APP_TYPE);
+        });
+    }
+
+}
diff --git a/src/main/java/org/codelibs/fess/job/TriggeredJob.java b/src/main/java/org/codelibs/fess/app/job/ScriptExecutorJob.java
similarity index 69%
rename from src/main/java/org/codelibs/fess/job/TriggeredJob.java
rename to src/main/java/org/codelibs/fess/app/job/ScriptExecutorJob.java
index d8160fd54da6b8ef9eed9ad31f9e1ffb72cbaa57..babac6ceef802c2373caf97c8f9dc37fd515e88a 100644
--- a/src/main/java/org/codelibs/fess/job/TriggeredJob.java
+++ b/src/main/java/org/codelibs/fess/app/job/ScriptExecutorJob.java
@@ -13,50 +13,44 @@
  * either express or implied. See the License for the specific language
  * governing permissions and limitations under the License.
  */
-package org.codelibs.fess.job;
+package org.codelibs.fess.app.job;
 
 import org.codelibs.fess.Constants;
 import org.codelibs.fess.app.service.JobLogService;
 import org.codelibs.fess.es.config.exentity.JobLog;
 import org.codelibs.fess.es.config.exentity.ScheduledJob;
-import org.codelibs.fess.helper.JobHelper;
 import org.codelibs.fess.helper.SystemHelper;
+import org.codelibs.fess.job.JobExecutor;
+import org.codelibs.fess.job.ScheduledJobException;
 import org.codelibs.fess.util.ComponentUtil;
 import org.lastaflute.di.core.SingletonLaContainer;
-import org.quartz.Job;
-import org.quartz.JobDataMap;
-import org.quartz.JobExecutionContext;
-import org.quartz.JobExecutionException;
+import org.lastaflute.job.JobManager;
+import org.lastaflute.job.LaJob;
+import org.lastaflute.job.LaJobRuntime;
+import org.lastaflute.job.key.LaJobUnique;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public class TriggeredJob implements Job {
-    private static final Logger logger = LoggerFactory.getLogger(TriggeredJob.class);
+public class ScriptExecutorJob implements LaJob {
+    private static final Logger logger = LoggerFactory.getLogger(ScriptExecutorJob.class);
 
     @Override
-    public void execute(final JobExecutionContext context) throws JobExecutionException {
-        final JobDataMap data = context.getMergedJobDataMap();
-        final ScheduledJob scheduledJob = (ScheduledJob) data.get(Constants.SCHEDULED_JOB);
-
-        execute(scheduledJob);
-    }
-
-    public void execute(final ScheduledJob scheduledJob) {
+    public void run(LaJobRuntime runtime) {
+        final ScheduledJob scheduledJob = (ScheduledJob) runtime.getParameterMap().get(Constants.SCHEDULED_JOB); // TODO null check
         final SystemHelper systemHelper = ComponentUtil.getSystemHelper();
-        final JobHelper jobHelper = ComponentUtil.getJobHelper();
+        final JobManager jobManager = ComponentUtil.getJobManager();
         final JobLog jobLog = new JobLog(scheduledJob);
         final String scriptType = scheduledJob.getScriptType();
         final String script = scheduledJob.getScriptData();
         final String id = scheduledJob.getId();
-        final String jobId = Constants.JOB_ID_PREFIX + id;
         final JobExecutor jobExecutor = ComponentUtil.getJobExecutor(scriptType);
         if (jobExecutor == null) {
             throw new ScheduledJobException("No jobExecutor: " + scriptType);
         }
 
-        if (jobHelper.startJobExecutoer(id, jobExecutor) != null) {
+        if (!jobManager.findJobByUniqueOf(LaJobUnique.of(id)).isPresent()) {
             if (logger.isDebugEnabled()) {
-                logger.debug(jobId + " is running.");
+                logger.debug("Job " + id + " is running.");
             }
             return;
         }
@@ -67,29 +61,28 @@ public class TriggeredJob implements Job {
             }
 
             if (logger.isDebugEnabled()) {
-                logger.debug("Starting Job " + jobId + ". scriptType: " + scriptType + ", script: " + script);
+                logger.debug("Starting Job " + id + ". scriptType: " + scriptType + ", script: " + script);
             } else if (scheduledJob.isLoggingEnabled() && logger.isInfoEnabled()) {
-                logger.info("Starting Job " + jobId + ".");
+                logger.info("Starting Job " + id + ".");
             }
 
             final Object ret = jobExecutor.execute(script);
             if (ret == null) {
                 if (scheduledJob.isLoggingEnabled() && logger.isInfoEnabled()) {
-                    logger.info("Finished Job " + jobId + ".");
+                    logger.info("Finished Job " + id + ".");
                 }
             } else {
                 if (scheduledJob.isLoggingEnabled() && logger.isInfoEnabled()) {
-                    logger.info("Finished Job " + jobId + ". The return value is:\n" + ret);
+                    logger.info("Finished Job " + id + ". The return value is:\n" + ret);
                 }
                 jobLog.setScriptResult(ret.toString());
             }
             jobLog.setJobStatus(Constants.OK);
-        } catch (final Throwable t) { // NOPMD
-            logger.error("Failed to execute " + jobId + ": " + script, t);
+        } catch (final Throwable t) {
+            logger.error("Failed to execute " + id + ": " + script, t);
             jobLog.setJobStatus(Constants.FAIL);
             jobLog.setScriptResult(systemHelper.abbreviateLongText(t.getLocalizedMessage()));
         } finally {
-            jobHelper.finishJobExecutoer(id);
             jobLog.setEndTime(ComponentUtil.getSystemHelper().getCurrentTimeAsLong());
             if (logger.isDebugEnabled()) {
                 logger.debug("jobLog: " + jobLog);
diff --git a/src/main/java/org/codelibs/fess/app/logic/AccessContextLogic.java b/src/main/java/org/codelibs/fess/app/logic/AccessContextLogic.java
new file mode 100644
index 0000000000000000000000000000000000000000..b09b0b1cc95590cd9309abefd9dcc972a3565277
--- /dev/null
+++ b/src/main/java/org/codelibs/fess/app/logic/AccessContextLogic.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2012-2016 CodeLibs Project and the Others.
+ *
+ * Licensed 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.codelibs.fess.app.logic;
+
+import javax.annotation.Resource;
+
+import org.codelibs.fess.mylasta.action.FessUserBean;
+import org.dbflute.hook.AccessContext;
+import org.dbflute.optional.OptionalThing;
+import org.lastaflute.core.time.TimeManager;
+import org.lastaflute.db.dbflute.accesscontext.AccessContextResource;
+
+public class AccessContextLogic {
+
+    // ===================================================================================
+    //                                                                           Attribute
+    //                                                                           =========
+    @Resource
+    private TimeManager timeManager;
+
+    // ===================================================================================
+    //                                                                  Resource Interface
+    //                                                                  ==================
+    @FunctionalInterface
+    public static interface UserTypeSupplier {
+        OptionalThing<String> supply();
+    }
+
+    @FunctionalInterface
+    public static interface UserBeanSupplier {
+        OptionalThing<FessUserBean> supply();
+    }
+
+    @FunctionalInterface
+    public static interface AppTypeSupplier {
+        String supply();
+    }
+
+    // ===================================================================================
+    //                                                                      Create Context
+    //                                                                      ==============
+    public AccessContext create(AccessContextResource resource, UserTypeSupplier userTypeSupplier, UserBeanSupplier userBeanSupplier,
+            AppTypeSupplier appTypeSupplier) {
+        final AccessContext context = new AccessContext();
+        context.setAccessLocalDateTimeProvider(() -> timeManager.currentDateTime());
+        context.setAccessUserProvider(() -> buildAccessUserTrace(resource, userTypeSupplier, userBeanSupplier, appTypeSupplier));
+        return context;
+    }
+
+    private <ID> String buildAccessUserTrace(AccessContextResource resource, UserTypeSupplier userTypeSupplier,
+            UserBeanSupplier userBeanSupplier, AppTypeSupplier appTypeSupplier) {
+        final StringBuilder sb = new StringBuilder();
+        sb.append(userTypeSupplier.supply().orElse("_"));
+        sb.append(",").append(appTypeSupplier.supply()).append(",").append(resource.getModuleName());
+        final String trace = sb.toString();
+        final int columnSize = 200;
+        return trace.length() > columnSize ? trace.substring(0, columnSize) : trace;
+    }
+}
diff --git a/src/main/java/org/codelibs/fess/app/service/ScheduledJobService.java b/src/main/java/org/codelibs/fess/app/service/ScheduledJobService.java
index 6ee8ce7cf8d0d503ce2eec60ff43d31cbf7716a1..5073c62492f85859d55d53d554dbdefbd4021cdc 100644
--- a/src/main/java/org/codelibs/fess/app/service/ScheduledJobService.java
+++ b/src/main/java/org/codelibs/fess/app/service/ScheduledJobService.java
@@ -16,27 +16,44 @@
 package org.codelibs.fess.app.service;
 
 import java.io.Serializable;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 import javax.annotation.Resource;
 
 import org.codelibs.core.beans.util.BeanUtil;
+import org.codelibs.core.lang.StringUtil;
 import org.codelibs.fess.Constants;
 import org.codelibs.fess.app.pager.SchedulerPager;
 import org.codelibs.fess.es.config.cbean.ScheduledJobCB;
 import org.codelibs.fess.es.config.exbhv.ScheduledJobBhv;
 import org.codelibs.fess.es.config.exentity.ScheduledJob;
-import org.codelibs.fess.job.JobScheduler;
+import org.codelibs.fess.job.ScheduledJobException;
+import org.codelibs.fess.mylasta.direction.FessConfig;
+import org.codelibs.fess.util.ComponentUtil;
 import org.dbflute.cbean.result.PagingResultBean;
 import org.dbflute.optional.OptionalEntity;
+import org.dbflute.optional.OptionalThing;
+import org.lastaflute.job.JobManager;
+import org.lastaflute.job.LaCron;
+import org.lastaflute.job.LaScheduledJob;
+import org.lastaflute.job.key.LaJobUnique;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 public class ScheduledJobService implements Serializable {
 
     private static final long serialVersionUID = 1L;
 
+    private static final Logger logger = LoggerFactory.getLogger(ScheduledJobService.class);
+
     @Resource
     protected ScheduledJobBhv scheduledJobBhv;
 
+    @Resource
+    protected FessConfig fessConfig;
+
     public List<ScheduledJob> getScheduledJobList(final SchedulerPager scheduledJobPager) {
 
         final PagingResultBean<ScheduledJob> scheduledJobList = scheduledJobBhv.selectPage(cb -> {
@@ -65,9 +82,6 @@ public class ScheduledJobService implements Serializable {
 
     }
 
-    @Resource
-    protected JobScheduler jobScheduler;
-
     protected void setupListCondition(final ScheduledJobCB cb, final SchedulerPager scheduledJobPager) {
         if (scheduledJobPager.id != null) {
             cb.query().docMeta().setId_Equal(scheduledJobPager.id);
@@ -90,15 +104,12 @@ public class ScheduledJobService implements Serializable {
     }
 
     public void store(final ScheduledJob scheduledJob) {
-        final boolean isNew = scheduledJob.getId() == null;
 
         scheduledJobBhv.insertOrUpdate(scheduledJob, op -> {
             op.setRefresh(true);
         });
-        if (!isNew) {
-            jobScheduler.unregister(scheduledJob);
-        }
-        jobScheduler.register(scheduledJob);
+        JobManager jobManager = ComponentUtil.getJobManager();
+        jobManager.schedule(cron -> register(cron, scheduledJob));
     }
 
     public List<ScheduledJob> getCrawlerJobList() {
@@ -109,4 +120,99 @@ public class ScheduledJobService implements Serializable {
         });
     }
 
+    protected void register(LaCron cron, final ScheduledJob scheduledJob) {
+        if (scheduledJob == null) {
+            throw new ScheduledJobException("No job.");
+        }
+
+        final String id = scheduledJob.getId();
+        if (!Constants.T.equals(scheduledJob.getAvailable())) {
+            logger.info("Inactive Job " + id + ":" + scheduledJob.getName());
+            try {
+                unregister(scheduledJob);
+            } catch (final Exception e) {
+                // ignore
+            }
+            return;
+        }
+
+        final String target = scheduledJob.getTarget();
+        if (!isTarget(target)) {
+            logger.info("Ignore Job " + id + ":" + scheduledJob.getName() + " because of not target: " + scheduledJob.getTarget());
+            return;
+        }
+
+        if (StringUtil.isNotBlank(scheduledJob.getCronExpression())) {
+            logger.info("Starting Job " + id + ":" + scheduledJob.getName());
+            findJobByUniqueOf(LaJobUnique.of(id)).ifPresent(job -> {
+                job.reschedule(scheduledJob.getCronExpression(), option -> option.uniqueBy(id).changeNoticeLogToDebug().params(() -> {
+                    Map<String, Object> params = new HashMap<>();
+                    params.put(Constants.SCHEDULED_JOB, scheduledJob);
+                    return params;
+                }));
+            }).orElse(
+                    () -> {
+                        cron.register(scheduledJob.getCronExpression(), fessConfig.getSchedulerJobClassAsClass(),
+                                fessConfig.getSchedulerConcurrentExecModeAsEnum(), option -> option.uniqueBy(id).changeNoticeLogToDebug()
+                                        .params(() -> {
+                                            Map<String, Object> params = new HashMap<>();
+                                            params.put(Constants.SCHEDULED_JOB, scheduledJob);
+                                            return params;
+                                        }));
+                    });
+        } else {
+            logger.info("Inactive Job " + id + ":" + scheduledJob.getName());
+            unregister(scheduledJob);
+        }
+    }
+
+    private OptionalThing<LaScheduledJob> findJobByUniqueOf(LaJobUnique jobUnique) {
+        final JobManager jobManager = ComponentUtil.getJobManager();
+        try {
+            return jobManager.findJobByUniqueOf(jobUnique);
+        } catch (Exception e) {
+            return OptionalThing.empty();
+        }
+    }
+
+    public void unregister(final ScheduledJob scheduledJob) {
+        try {
+            JobManager jobManager = ComponentUtil.getJobManager();
+            jobManager.findJobByUniqueOf(LaJobUnique.of(scheduledJob.getId())).ifPresent(job -> {
+                job.unschedule();
+            }).orElse(() -> logger.debug("Job {} is not scheduled.", scheduledJob.getId()));
+        } catch (final Exception e) {
+            throw new ScheduledJobException("Failed to delete Job: " + scheduledJob, e);
+        }
+    }
+
+    protected boolean isTarget(final String target) {
+        if (StringUtil.isBlank(target))
+
+        {
+            return true;
+        }
+
+        final FessConfig fessConfig = ComponentUtil.getFessConfig();
+        final String myName = fessConfig.getSchedulerTargetName();
+
+        final String[] targets = target.split(",");
+        for (String name : targets) {
+            name = name.trim();
+            if (Constants.DEFAULT_JOB_TARGET.equalsIgnoreCase(name)) {
+                return true;
+            } else if (StringUtil.isNotBlank(myName) && myName.equalsIgnoreCase(name)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public void start(LaCron cron) {
+        scheduledJobBhv.selectCursor(cb -> {
+            cb.query().setAvailable_Equal(Constants.T);
+            cb.query().addOrderBy_SortOrder_Asc();
+            cb.query().addOrderBy_Name_Asc();
+        }, scheduledJob -> register(cron, scheduledJob));
+    }
 }
diff --git a/src/main/java/org/codelibs/fess/app/web/admin/crawlinginfo/AdminCrawlinginfoAction.java b/src/main/java/org/codelibs/fess/app/web/admin/crawlinginfo/AdminCrawlinginfoAction.java
index 9247e543cceeaf44785f6ad35d11dc13e5cea9cb..7d9e1f1da59d6cf8bd9fa42ff3d349255b6cf6f0 100644
--- a/src/main/java/org/codelibs/fess/app/web/admin/crawlinginfo/AdminCrawlinginfoAction.java
+++ b/src/main/java/org/codelibs/fess/app/web/admin/crawlinginfo/AdminCrawlinginfoAction.java
@@ -22,7 +22,7 @@ import org.codelibs.fess.app.pager.CrawlingInfoPager;
 import org.codelibs.fess.app.service.CrawlingInfoService;
 import org.codelibs.fess.app.web.CrudMode;
 import org.codelibs.fess.app.web.base.FessAdminAction;
-import org.codelibs.fess.helper.JobHelper;
+import org.codelibs.fess.helper.ProcessHelper;
 import org.codelibs.fess.helper.SystemHelper;
 import org.codelibs.fess.util.RenderDataUtil;
 import org.lastaflute.web.Execute;
@@ -46,7 +46,7 @@ public class AdminCrawlinginfoAction extends FessAdminAction {
     @Resource
     private SystemHelper systemHelper;
     @Resource
-    protected JobHelper jobHelper;
+    protected ProcessHelper processHelper;
 
     // ===================================================================================
     //                                                                               Hook
@@ -154,7 +154,7 @@ public class AdminCrawlinginfoAction extends FessAdminAction {
     @Execute
     public HtmlResponse deleteall() {
         verifyToken(() -> asListHtml());
-        crawlingInfoService.deleteOldSessions(jobHelper.getRunningSessionIdSet());
+        crawlingInfoService.deleteOldSessions(processHelper.getRunningSessionIdSet());
         crawlingInfoPager.clear();
         saveInfo(messages -> messages.addSuccessCrawlingInfoDeleteAll(GLOBAL));
         return redirect(getClass());
diff --git a/src/main/java/org/codelibs/fess/app/web/admin/scheduler/AdminSchedulerAction.java b/src/main/java/org/codelibs/fess/app/web/admin/scheduler/AdminSchedulerAction.java
index 23e57f325e9190d7305a6300be4581493d60780a..9ba64c6d2b0e33a333005b227639ad6473955b55 100644
--- a/src/main/java/org/codelibs/fess/app/web/admin/scheduler/AdminSchedulerAction.java
+++ b/src/main/java/org/codelibs/fess/app/web/admin/scheduler/AdminSchedulerAction.java
@@ -25,9 +25,8 @@ import org.codelibs.fess.app.service.ScheduledJobService;
 import org.codelibs.fess.app.web.CrudMode;
 import org.codelibs.fess.app.web.base.FessAdminAction;
 import org.codelibs.fess.es.config.exentity.ScheduledJob;
-import org.codelibs.fess.helper.JobHelper;
+import org.codelibs.fess.helper.ProcessHelper;
 import org.codelibs.fess.helper.SystemHelper;
-import org.codelibs.fess.job.JobExecutor;
 import org.codelibs.fess.util.RenderDataUtil;
 import org.dbflute.optional.OptionalEntity;
 import org.dbflute.optional.OptionalThing;
@@ -53,7 +52,7 @@ public class AdminSchedulerAction extends FessAdminAction {
     @Resource
     private SystemHelper systemHelper;
     @Resource
-    protected JobHelper jobHelper;
+    protected ProcessHelper processHelper;
 
     // ===================================================================================
     //                                                                               Hook
@@ -271,8 +270,7 @@ public class AdminSchedulerAction extends FessAdminAction {
         verifyToken(() -> asDetailsHtml(id));
         scheduledJobService.getScheduledJob(id).ifPresent(entity -> {
             try {
-                final JobExecutor jobExecutoer = jobHelper.getJobExecutoer(entity.getId());
-                jobExecutoer.shutdown();
+                entity.stop();
                 saveInfo(messages -> messages.addSuccessJobStopped(GLOBAL, entity.getName()));
             } catch (final Exception e) {
                 throwValidationError(messages -> {
diff --git a/src/main/java/org/codelibs/fess/app/web/admin/searchlist/AdminSearchlistAction.java b/src/main/java/org/codelibs/fess/app/web/admin/searchlist/AdminSearchlistAction.java
index 3578e5df203ebfe5e605152e0f9bd320b042f130..1f49d7c55372a7b09690a95d7f7999382b26c067 100644
--- a/src/main/java/org/codelibs/fess/app/web/admin/searchlist/AdminSearchlistAction.java
+++ b/src/main/java/org/codelibs/fess/app/web/admin/searchlist/AdminSearchlistAction.java
@@ -29,7 +29,7 @@ import org.codelibs.fess.entity.SearchRenderData;
 import org.codelibs.fess.es.client.FessEsClient;
 import org.codelibs.fess.exception.InvalidQueryException;
 import org.codelibs.fess.exception.ResultOffsetExceededException;
-import org.codelibs.fess.helper.JobHelper;
+import org.codelibs.fess.helper.ProcessHelper;
 import org.codelibs.fess.helper.QueryHelper;
 import org.codelibs.fess.helper.SystemHelper;
 import org.codelibs.fess.util.RenderDataUtil;
@@ -66,7 +66,7 @@ public class AdminSearchlistAction extends FessAdminAction {
     protected QueryHelper queryHelper;
 
     @Resource
-    protected JobHelper jobHelper;
+    protected ProcessHelper processHelper;
 
     @Resource
     protected SearchService searchService;
@@ -194,7 +194,7 @@ public class AdminSearchlistAction extends FessAdminAction {
         verifyToken(() -> asListHtml());
         validate(form, messages -> {}, () -> asListHtml());
         final String docId = form.docId;
-        if (jobHelper.isProcessRunning()) {
+        if (processHelper.isProcessRunning()) {
             throwValidationError(messages -> messages.addErrorsCannotDeleteDocBecauseOfRunning(GLOBAL), () -> asListHtml());
         }
         try {
@@ -211,7 +211,7 @@ public class AdminSearchlistAction extends FessAdminAction {
     public HtmlResponse deleteall(final ListForm form) {
         verifyToken(() -> asListHtml());
         validate(form, messages -> {}, () -> asListHtml());
-        if (jobHelper.isProcessRunning()) {
+        if (processHelper.isProcessRunning()) {
             throwValidationError(messages -> messages.addErrorsCannotDeleteDocBecauseOfRunning(GLOBAL), () -> asListHtml());
         }
         try {
@@ -227,7 +227,7 @@ public class AdminSearchlistAction extends FessAdminAction {
     }
 
     public boolean isSolrProcessRunning() {
-        return jobHelper.isProcessRunning();
+        return processHelper.isProcessRunning();
     }
 
     // ===================================================================================
diff --git a/src/main/java/org/codelibs/fess/app/web/admin/wizard/AdminWizardAction.java b/src/main/java/org/codelibs/fess/app/web/admin/wizard/AdminWizardAction.java
index 78e91631d7b1c05ee6e421c3a77e8cf51cd0f64a..d7f71e99f2a7140a0774c431678e05943fa457b9 100644
--- a/src/main/java/org/codelibs/fess/app/web/admin/wizard/AdminWizardAction.java
+++ b/src/main/java/org/codelibs/fess/app/web/admin/wizard/AdminWizardAction.java
@@ -33,11 +33,12 @@ import org.codelibs.fess.crawler.util.CharUtil;
 import org.codelibs.fess.es.config.exentity.FileConfig;
 import org.codelibs.fess.es.config.exentity.ScheduledJob;
 import org.codelibs.fess.es.config.exentity.WebConfig;
-import org.codelibs.fess.helper.JobHelper;
+import org.codelibs.fess.helper.ProcessHelper;
 import org.codelibs.fess.helper.SystemHelper;
-import org.codelibs.fess.job.TriggeredJob;
 import org.codelibs.fess.util.ComponentUtil;
 import org.codelibs.fess.util.StreamUtil;
+import org.lastaflute.job.JobManager;
+import org.lastaflute.job.key.LaJobUnique;
 import org.lastaflute.web.Execute;
 import org.lastaflute.web.response.HtmlResponse;
 import org.lastaflute.web.ruts.process.ActionRuntime;
@@ -67,7 +68,7 @@ public class AdminWizardAction extends FessAdminAction {
     protected SystemHelper systemHelper;
 
     @Resource
-    protected JobHelper jobHelper;
+    protected ProcessHelper processHelper;
 
     @Resource
     protected ScheduledJobService scheduledJobService;
@@ -289,10 +290,13 @@ public class AdminWizardAction extends FessAdminAction {
     @Execute
     public HtmlResponse startCrawling(final StartCrawlingForm form) {
         verifyToken(() -> asIndexHtml());
-        if (!jobHelper.isProcessRunning()) {
+        if (!processHelper.isProcessRunning()) {
             final List<ScheduledJob> scheduledJobList = scheduledJobService.getCrawlerJobList();
+            JobManager jobManager = ComponentUtil.getJobManager();
             for (final ScheduledJob scheduledJob : scheduledJobList) {
-                new Thread(() -> new TriggeredJob().execute(scheduledJob)).start();
+                jobManager.findJobByUniqueOf(LaJobUnique.of(scheduledJob.getId())).ifPresent(job -> {
+                    job.launchNow();
+                });
             }
             saveInfo(messages -> messages.addSuccessStartCrawlProcess(GLOBAL));
         } else {
diff --git a/src/main/java/org/codelibs/fess/es/config/exentity/ScheduledJob.java b/src/main/java/org/codelibs/fess/es/config/exentity/ScheduledJob.java
index de78a066f063e22c24a373a0a957c854784a2b8c..53ac1e427fb271c4f824aaceb7dc09ee15a6aac4 100644
--- a/src/main/java/org/codelibs/fess/es/config/exentity/ScheduledJob.java
+++ b/src/main/java/org/codelibs/fess/es/config/exentity/ScheduledJob.java
@@ -15,10 +15,11 @@
  */
 package org.codelibs.fess.es.config.exentity;
 
+import org.codelibs.core.lang.StringUtil;
 import org.codelibs.fess.Constants;
 import org.codelibs.fess.es.config.bsentity.BsScheduledJob;
-import org.codelibs.fess.job.TriggeredJob;
 import org.codelibs.fess.util.ComponentUtil;
+import org.lastaflute.job.key.LaJobUnique;
 
 /**
  * @author FreeGen
@@ -27,6 +28,14 @@ public class ScheduledJob extends BsScheduledJob {
 
     private static final long serialVersionUID = 1L;
 
+    public String getScriptType() {
+        String st = super.getScriptType();
+        if (StringUtil.isBlank(st)) {
+            return "groovy";
+        }
+        return st;
+    }
+
     public boolean isLoggingEnabled() {
         return Constants.T.equals(getJobLogging());
     }
@@ -40,12 +49,19 @@ public class ScheduledJob extends BsScheduledJob {
     }
 
     public boolean isRunning() {
-        return ComponentUtil.getJobHelper().getJobExecutoer(getId()) != null;
+        return ComponentUtil.getJobManager().findJobByUniqueOf(LaJobUnique.of(getId())).map(job -> job.isExecutingNow()).orElse(false);
     }
 
     public void start() {
-        final ScheduledJob scheduledJob = this;
-        new Thread(() -> new TriggeredJob().execute(scheduledJob)).start();
+        ComponentUtil.getJobManager().findJobByUniqueOf(LaJobUnique.of(getId())).ifPresent(job -> {
+            job.launchNow();
+        });
+    }
+
+    public void stop() {
+        ComponentUtil.getJobManager().findJobByUniqueOf(LaJobUnique.of(getId())).ifPresent(job -> {
+            job.stopNow();
+        });
     }
 
     public String getId() {
diff --git a/src/main/java/org/codelibs/fess/helper/JobHelper.java b/src/main/java/org/codelibs/fess/helper/ProcessHelper.java
similarity index 87%
rename from src/main/java/org/codelibs/fess/helper/JobHelper.java
rename to src/main/java/org/codelibs/fess/helper/ProcessHelper.java
index e983bc2624b5f7d1e4e0593a67a4c49dde6d3dbe..619554a76375fb14a9091d24a93074ddecac9429 100644
--- a/src/main/java/org/codelibs/fess/helper/JobHelper.java
+++ b/src/main/java/org/codelibs/fess/helper/ProcessHelper.java
@@ -27,19 +27,16 @@ import javax.annotation.PreDestroy;
 
 import org.apache.commons.io.IOUtils;
 import org.codelibs.fess.exception.FessSystemException;
-import org.codelibs.fess.job.JobExecutor;
 import org.codelibs.fess.util.InputStreamThread;
 import org.codelibs.fess.util.JobProcess;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public class JobHelper {
-    private static final Logger logger = LoggerFactory.getLogger(JobHelper.class);
+public class ProcessHelper {
+    private static final Logger logger = LoggerFactory.getLogger(ProcessHelper.class);
 
     private final ConcurrentHashMap<String, JobProcess> runningProcessMap = new ConcurrentHashMap<>();
 
-    private final ConcurrentHashMap<String, JobExecutor> runningJobExecutorMap = new ConcurrentHashMap<>();
-
     @PreDestroy
     public void destroy() {
         for (final String sessionId : runningProcessMap.keySet()) {
@@ -117,16 +114,4 @@ public class JobHelper {
         return runningProcessMap.keySet();
     }
 
-    public JobExecutor startJobExecutoer(final String id, final JobExecutor jobExecutor) {
-        return runningJobExecutorMap.putIfAbsent(id, jobExecutor);
-    }
-
-    public void finishJobExecutoer(final String id) {
-        runningJobExecutorMap.remove(id);
-    }
-
-    public JobExecutor getJobExecutoer(final String id) {
-        return runningJobExecutorMap.get(id);
-    }
-
 }
diff --git a/src/main/java/org/codelibs/fess/helper/SystemHelper.java b/src/main/java/org/codelibs/fess/helper/SystemHelper.java
index 208969c27a1a9c8c4e9bc100860674e2a46000c1..a7757d935ae846e376f5f04061ecb7204af7a462 100644
--- a/src/main/java/org/codelibs/fess/helper/SystemHelper.java
+++ b/src/main/java/org/codelibs/fess/helper/SystemHelper.java
@@ -35,6 +35,7 @@ import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
 
 import org.apache.commons.lang3.LocaleUtils;
 import org.apache.commons.lang3.StringUtils;
@@ -49,6 +50,8 @@ import org.codelibs.fess.util.ComponentUtil;
 import org.lastaflute.di.core.SingletonLaContainer;
 import org.lastaflute.web.servlet.request.RequestManager;
 import org.lastaflute.web.util.LaRequestUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import com.google.common.cache.CacheBuilder;
 import com.google.common.cache.CacheLoader;
@@ -56,6 +59,7 @@ import com.google.common.cache.LoadingCache;
 import com.ibm.icu.util.ULocale;
 
 public class SystemHelper implements Serializable {
+    private static final Logger logger = LoggerFactory.getLogger(SystemHelper.class);
 
     private static final long serialVersionUID = 1L;
 
@@ -71,6 +75,8 @@ public class SystemHelper implements Serializable {
 
     private String[] supportedLanguages;
 
+    private List<Runnable> shutdownHookList = new ArrayList<>();
+
     @PostConstruct
     public void init() {
         final FessConfig fessConfig = ComponentUtil.getFessConfig();
@@ -103,6 +109,17 @@ public class SystemHelper implements Serializable {
                         });
     }
 
+    @PreDestroy
+    public void destroy() {
+        shutdownHookList.forEach(action -> {
+            try {
+                action.run();
+            } catch (Exception e) {
+                logger.warn("Failed to process shutdown task.", e);
+            }
+        });
+    }
+
     public String getUsername() {
         final RequestManager requestManager = ComponentUtil.getRequestManager();
         return requestManager.findUserBean(FessUserBean.class).map(user -> {
@@ -252,4 +269,16 @@ public class SystemHelper implements Serializable {
         }
     }
 
+    public void sleep(int sec) {
+        try {
+            Thread.sleep(sec * 1000L);
+        } catch (InterruptedException e) {
+            // ignore
+        }
+    }
+
+    public void addShutdownHook(Runnable hook) {
+        shutdownHookList.add(hook);
+    }
+
 }
diff --git a/src/main/java/org/codelibs/fess/job/CrawlJob.java b/src/main/java/org/codelibs/fess/job/CrawlJob.java
index c88c58a15877bb7e2570d9750d3c33e3f46b7473..bfc195ec7ea4f2d9c0aa7011ddcdb0b3f25189de 100644
--- a/src/main/java/org/codelibs/fess/job/CrawlJob.java
+++ b/src/main/java/org/codelibs/fess/job/CrawlJob.java
@@ -32,7 +32,7 @@ import org.codelibs.core.lang.StringUtil;
 import org.codelibs.fess.Constants;
 import org.codelibs.fess.exception.FessSystemException;
 import org.codelibs.fess.exec.Crawler;
-import org.codelibs.fess.helper.JobHelper;
+import org.codelibs.fess.helper.ProcessHelper;
 import org.codelibs.fess.helper.SystemHelper;
 import org.codelibs.fess.mylasta.direction.FessConfig;
 import org.codelibs.fess.util.ComponentUtil;
@@ -231,7 +231,7 @@ public class CrawlJob {
         final String cpSeparator = SystemUtils.IS_OS_WINDOWS ? ";" : ":";
         final ServletContext servletContext = SingletonLaContainer.getComponent(ServletContext.class);
         final SystemHelper systemHelper = ComponentUtil.getSystemHelper();
-        final JobHelper jobHelper = ComponentUtil.getJobHelper();
+        final ProcessHelper processHelper = ComponentUtil.getJobHelper();
         final FessConfig fessConfig = ComponentUtil.getFessConfig();
 
         cmdList.add(fessConfig.getJavaCommandPath());
@@ -361,7 +361,7 @@ public class CrawlJob {
                 logger.info("Crawler: \nDirectory=" + baseDir + "\nOptions=" + cmdList);
             }
 
-            final JobProcess jobProcess = jobHelper.startProcess(sessionId, cmdList, pb -> {
+            final JobProcess jobProcess = processHelper.startProcess(sessionId, cmdList, pb -> {
                 pb.directory(baseDir);
                 pb.redirectErrorStream(true);
             });
@@ -389,7 +389,7 @@ public class CrawlJob {
             throw new FessSystemException("Crawler Process terminated.", e);
         } finally {
             try {
-                jobHelper.destroyProcess(sessionId);
+                processHelper.destroyProcess(sessionId);
             } finally {
                 if (propFile != null && !propFile.delete()) {
                     logger.warn("Failed to delete {}.", propFile.getAbsolutePath());
diff --git a/src/main/java/org/codelibs/fess/job/JobScheduler.java b/src/main/java/org/codelibs/fess/job/JobScheduler.java
deleted file mode 100644
index cf4f683faabaf185c94f32b154a3616a52eda46d..0000000000000000000000000000000000000000
--- a/src/main/java/org/codelibs/fess/job/JobScheduler.java
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * Copyright 2012-2016 CodeLibs Project and the Others.
- *
- * Licensed 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.codelibs.fess.job;
-
-import static org.quartz.CronScheduleBuilder.cronSchedule;
-import static org.quartz.JobBuilder.newJob;
-import static org.quartz.JobKey.jobKey;
-import static org.quartz.TriggerBuilder.newTrigger;
-
-import javax.annotation.PostConstruct;
-import javax.annotation.PreDestroy;
-
-import org.codelibs.core.lang.StringUtil;
-import org.codelibs.fess.Constants;
-import org.codelibs.fess.es.config.exbhv.JobLogBhv;
-import org.codelibs.fess.es.config.exbhv.ScheduledJobBhv;
-import org.codelibs.fess.es.config.exentity.ScheduledJob;
-import org.codelibs.fess.helper.JobHelper;
-import org.codelibs.fess.mylasta.direction.FessConfig;
-import org.codelibs.fess.util.ComponentUtil;
-import org.quartz.Job;
-import org.quartz.JobDataMap;
-import org.quartz.JobDetail;
-import org.quartz.Scheduler;
-import org.quartz.SchedulerException;
-import org.quartz.SchedulerFactory;
-import org.quartz.Trigger;
-import org.quartz.impl.StdSchedulerFactory;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class JobScheduler {
-    private static final Logger logger = LoggerFactory.getLogger(JobScheduler.class);
-
-    private static final String TRIGGER_ID_PREFIX = "trigger";
-
-    private Scheduler scheduler;
-
-    public Class<? extends Job> jobClass = TriggeredJob.class;
-
-    @PostConstruct
-    public void init() {
-        final SchedulerFactory sf = new StdSchedulerFactory();
-        try {
-            scheduler = sf.getScheduler();
-            scheduler.start();
-        } catch (final SchedulerException e) {
-            throw new ScheduledJobException("Failed to start a scheduler.", e);
-        }
-
-        ComponentUtil.getComponent(ScheduledJobBhv.class).selectCursor(cb -> {
-            cb.query().setAvailable_Equal(Constants.T);
-            cb.query().addOrderBy_SortOrder_Asc();
-            cb.query().addOrderBy_Name_Asc();
-        }, scheduledJob -> register(scheduledJob));
-
-        final FessConfig fessConfig = ComponentUtil.getFessConfig();
-        final String myName = fessConfig.getSchedulerTargetName();
-        if (StringUtil.isNotBlank(myName)) {
-            ComponentUtil.getComponent(JobLogBhv.class).queryDelete(cb -> {
-                cb.query().setJobStatus_Equal(Constants.RUNNING);
-                cb.query().setTarget_Equal(myName);
-            });
-        }
-    }
-
-    @PreDestroy
-    public void destroy() {
-        final JobHelper jobHelper = ComponentUtil.getJobHelper();
-        for (final String sessionId : jobHelper.getRunningSessionIdSet()) {
-            jobHelper.destroyProcess(sessionId);
-        }
-        try {
-            scheduler.shutdown(true);
-        } catch (final SchedulerException e) {
-            logger.error("Failed to shutdown the scheduler.", e);
-        }
-    }
-
-    public void register(final ScheduledJob scheduledJob) {
-        if (scheduledJob == null) {
-            throw new ScheduledJobException("No job.");
-        }
-
-        if (!Constants.T.equals(scheduledJob.getAvailable())) {
-            logger.info("Inactive Job " + scheduledJob.getId() + ":" + scheduledJob.getName());
-            try {
-                unregister(scheduledJob);
-            } catch (final Exception e) {
-                // ignore
-            }
-            return;
-        }
-
-        final String target = scheduledJob.getTarget();
-        if (!isTarget(target)) {
-            logger.info("Ignore Job " + scheduledJob.getId() + ":" + scheduledJob.getName() + " because of not target: "
-                    + scheduledJob.getTarget());
-            return;
-        }
-
-        String scriptType = scheduledJob.getScriptType();
-        if (scriptType == null) {
-            scriptType = "groovy";
-        }
-
-        final String id = scheduledJob.getId();
-        final String jobId = Constants.JOB_ID_PREFIX + id;
-        final String triggerId = TRIGGER_ID_PREFIX + id;
-
-        final JobDataMap jobDataMap = new JobDataMap();
-        jobDataMap.put(Constants.SCHEDULED_JOB, scheduledJob);
-        jobDataMap.put(Constants.JOB_EXECUTOR_TYPE, scriptType);
-        final JobDetail jobDetail = newJob(jobClass).withIdentity(jobId).usingJobData(jobDataMap).build();
-
-        if (StringUtil.isNotBlank(scheduledJob.getCronExpression())) {
-            final Trigger trigger =
-                    newTrigger().withIdentity(triggerId).withSchedule(cronSchedule(scheduledJob.getCronExpression())).startNow().build();
-
-            try {
-                scheduler.scheduleJob(jobDetail, trigger);
-            } catch (final SchedulerException e) {
-                throw new ScheduledJobException("Failed to add Job: " + scheduledJob, e);
-            }
-
-            logger.info("Starting Job " + scheduledJob.getId() + ":" + scheduledJob.getName());
-        }
-    }
-
-    public void unregister(final ScheduledJob scheduledJob) {
-        final String jobId = Constants.JOB_ID_PREFIX + scheduledJob.getId();
-        try {
-            scheduler.deleteJob(jobKey(jobId));
-        } catch (final SchedulerException e) {
-            throw new ScheduledJobException("Failed to delete Job: " + scheduledJob, e);
-        }
-    }
-
-    protected boolean isTarget(final String target) {
-        if (StringUtil.isBlank(target)) {
-            return true;
-        }
-
-        final FessConfig fessConfig = ComponentUtil.getFessConfig();
-        final String myName = fessConfig.getSchedulerTargetName();
-
-        final String[] targets = target.split(",");
-        for (String name : targets) {
-            name = name.trim();
-            if (Constants.DEFAULT_JOB_TARGET.equalsIgnoreCase(name)) {
-                return true;
-            } else if (StringUtil.isNotBlank(myName) && myName.equalsIgnoreCase(name)) {
-                return true;
-            }
-        }
-        return false;
-    }
-}
diff --git a/src/main/java/org/codelibs/fess/job/SuggestJob.java b/src/main/java/org/codelibs/fess/job/SuggestJob.java
index 6585dde502d30682647e25a2814ccaa3c2b32f36..7b6344102b198dd6688ff71e53142b0e5821854f 100644
--- a/src/main/java/org/codelibs/fess/job/SuggestJob.java
+++ b/src/main/java/org/codelibs/fess/job/SuggestJob.java
@@ -31,7 +31,7 @@ import org.codelibs.core.lang.StringUtil;
 import org.codelibs.fess.Constants;
 import org.codelibs.fess.exception.FessSystemException;
 import org.codelibs.fess.exec.SuggestCreator;
-import org.codelibs.fess.helper.JobHelper;
+import org.codelibs.fess.helper.ProcessHelper;
 import org.codelibs.fess.mylasta.direction.FessConfig;
 import org.codelibs.fess.util.ComponentUtil;
 import org.codelibs.fess.util.InputStreamThread;
@@ -122,7 +122,7 @@ public class SuggestJob {
         final List<String> cmdList = new ArrayList<>();
         final String cpSeparator = SystemUtils.IS_OS_WINDOWS ? ";" : ":";
         final ServletContext servletContext = SingletonLaContainer.getComponent(ServletContext.class);
-        final JobHelper jobHelper = ComponentUtil.getJobHelper();
+        final ProcessHelper processHelper = ComponentUtil.getJobHelper();
         final FessConfig fessConfig = ComponentUtil.getFessConfig();
 
         cmdList.add(fessConfig.getJavaCommandPath());
@@ -233,7 +233,7 @@ public class SuggestJob {
                 logger.info("SuggestCreator: \nDirectory=" + baseDir + "\nOptions=" + cmdList);
             }
 
-            final JobProcess jobProcess = jobHelper.startProcess(sessionId, cmdList, pb -> {
+            final JobProcess jobProcess = processHelper.startProcess(sessionId, cmdList, pb -> {
                 pb.directory(baseDir);
                 pb.redirectErrorStream(true);
             });
@@ -261,7 +261,7 @@ public class SuggestJob {
             throw new FessSystemException("SuggestCreator Process terminated.", e);
         } finally {
             try {
-                jobHelper.destroyProcess(sessionId);
+                processHelper.destroyProcess(sessionId);
             } finally {
                 if (propFile != null && !propFile.delete()) {
                     logger.warn("Failed to delete {}.", propFile.getAbsolutePath());
diff --git a/src/main/java/org/codelibs/fess/mylasta/direction/FessConfig.java b/src/main/java/org/codelibs/fess/mylasta/direction/FessConfig.java
index 4f0262a992348c4045d4825568d25749af8394d7..466dff5bdd6f3fc0cc3ee9d881335f79671853c5 100644
--- a/src/main/java/org/codelibs/fess/mylasta/direction/FessConfig.java
+++ b/src/main/java/org/codelibs/fess/mylasta/direction/FessConfig.java
@@ -384,6 +384,12 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
     /** The key of the configuration. e.g.  */
     String SCHEDULER_TARGET_NAME = "scheduler.target.name";
 
+    /** The key of the configuration. e.g. org.codelibs.fess.app.job.ScriptExecutorJob */
+    String SCHEDULER_JOB_CLASS = "scheduler.job.class";
+
+    /** The key of the configuration. e.g. QUIT */
+    String SCHEDULER_CONCURRENT_EXEC_MODE = "scheduler.concurrent.exec.mode";
+
     /** The key of the configuration. e.g. http://fess.codelibs.org/{lang}/{version}/admin/ */
     String ONLINE_HELP_BASE_LINK = "online.help.base.link";
 
@@ -1773,6 +1779,20 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
      */
     Integer getSchedulerTargetNameAsInteger();
 
+    /**
+     * Get the value for the key 'scheduler.job.class'. <br>
+     * The value is, e.g. org.codelibs.fess.app.job.ScriptExecutorJob <br>
+     * @return The value of found property. (NotNull: if not found, exception but basically no way)
+     */
+    String getSchedulerJobClass();
+
+    /**
+     * Get the value for the key 'scheduler.concurrent.exec.mode'. <br>
+     * The value is, e.g. QUIT <br>
+     * @return The value of found property. (NotNull: if not found, exception but basically no way)
+     */
+    String getSchedulerConcurrentExecMode();
+
     /**
      * Get the value for the key 'online.help.base.link'. <br>
      * The value is, e.g. http://fess.codelibs.org/{lang}/{version}/admin/ <br>
@@ -2834,6 +2854,14 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
             return getAsInteger(FessConfig.SCHEDULER_TARGET_NAME);
         }
 
+        public String getSchedulerJobClass() {
+            return get(FessConfig.SCHEDULER_JOB_CLASS);
+        }
+
+        public String getSchedulerConcurrentExecMode() {
+            return get(FessConfig.SCHEDULER_CONCURRENT_EXEC_MODE);
+        }
+
         public String getOnlineHelpBaseLink() {
             return get(FessConfig.ONLINE_HELP_BASE_LINK);
         }
diff --git a/src/main/java/org/codelibs/fess/mylasta/direction/FessProp.java b/src/main/java/org/codelibs/fess/mylasta/direction/FessProp.java
index a4b9ecd2f7c389b881fb668d12ff0ddaa526f0fa..1f261de07b40df1062fb2e1f9aafc387aad21ac7 100644
--- a/src/main/java/org/codelibs/fess/mylasta/direction/FessProp.java
+++ b/src/main/java/org/codelibs/fess/mylasta/direction/FessProp.java
@@ -15,10 +15,13 @@
  */
 package org.codelibs.fess.mylasta.direction;
 
+import org.codelibs.core.exception.ClassNotFoundRuntimeException;
 import org.codelibs.core.lang.StringUtil;
 import org.codelibs.fess.Constants;
 import org.codelibs.fess.util.ComponentUtil;
 import org.codelibs.fess.util.StreamUtil;
+import org.lastaflute.job.LaJob;
+import org.lastaflute.job.subsidiary.ConcurrentExec;
 
 public interface FessProp {
 
@@ -280,4 +283,22 @@ public interface FessProp {
         return "None";
     }
 
+    String getSchedulerJobClass();
+
+    public default Class<? extends LaJob> getSchedulerJobClassAsClass() {
+        try {
+            @SuppressWarnings("unchecked")
+            Class<? extends LaJob> clazz = (Class<? extends LaJob>) Class.forName(getSchedulerJobClass());
+            return clazz;
+        } catch (ClassNotFoundException e) {
+            throw new ClassNotFoundRuntimeException(e);
+        }
+    }
+
+    String getSchedulerConcurrentExecMode();
+
+    public default ConcurrentExec getSchedulerConcurrentExecModeAsEnum() {
+        return ConcurrentExec.valueOf(getSchedulerConcurrentExecMode());
+    }
+
 }
diff --git a/src/main/java/org/codelibs/fess/util/ComponentUtil.java b/src/main/java/org/codelibs/fess/util/ComponentUtil.java
index 603fc6e8e52b34848a05ed460fad381ebff298f8..fc09d75bcfc2e66bda896d4c34e6ea4c370d4216 100644
--- a/src/main/java/org/codelibs/fess/util/ComponentUtil.java
+++ b/src/main/java/org/codelibs/fess/util/ComponentUtil.java
@@ -30,11 +30,11 @@ import org.codelibs.fess.helper.DuplicateHostHelper;
 import org.codelibs.fess.helper.FileTypeHelper;
 import org.codelibs.fess.helper.IndexingHelper;
 import org.codelibs.fess.helper.IntervalControlHelper;
-import org.codelibs.fess.helper.JobHelper;
 import org.codelibs.fess.helper.KeyMatchHelper;
 import org.codelibs.fess.helper.LabelTypeHelper;
 import org.codelibs.fess.helper.PathMappingHelper;
 import org.codelibs.fess.helper.PopularWordHelper;
+import org.codelibs.fess.helper.ProcessHelper;
 import org.codelibs.fess.helper.QueryHelper;
 import org.codelibs.fess.helper.RoleQueryHelper;
 import org.codelibs.fess.helper.SambaHelper;
@@ -51,6 +51,7 @@ import org.codelibs.fess.mylasta.direction.FessConfig;
 import org.lastaflute.core.message.MessageManager;
 import org.lastaflute.di.core.SingletonLaContainer;
 import org.lastaflute.di.core.factory.SingletonLaContainerFactory;
+import org.lastaflute.job.JobManager;
 import org.lastaflute.web.servlet.request.RequestManager;
 
 public final class ComponentUtil {
@@ -86,7 +87,7 @@ public final class ComponentUtil {
 
     private static final String WEB_API_MANAGER_FACTORY = "webApiManagerFactory";
 
-    private static final String JOB_HELPER = "jobHelper";
+    private static final String JOB_HELPER = "processHelper";
 
     private static final String DUPLICATE_HOST_HELPER = "duplicateHostHelper";
 
@@ -187,7 +188,7 @@ public final class ComponentUtil {
         return SingletonLaContainer.getComponent(DUPLICATE_HOST_HELPER);
     }
 
-    public static JobHelper getJobHelper() {
+    public static ProcessHelper getJobHelper() {
         return SingletonLaContainer.getComponent(JOB_HELPER);
     }
 
@@ -279,6 +280,10 @@ public final class ComponentUtil {
         return SingletonLaContainer.getComponent(RequestManager.class);
     }
 
+    public static JobManager getJobManager() {
+        return SingletonLaContainer.getComponent(JobManager.class);
+    }
+
     public static <T> T getComponent(final Class<T> clazz) {
         return SingletonLaContainer.getComponent(clazz);
     }
diff --git a/src/main/java/org/codelibs/fess/validation/CronExpressionValidator.java b/src/main/java/org/codelibs/fess/validation/CronExpressionValidator.java
index f63cc3002d3159d170cf8a265c5a59fc194ff35a..4598bca8e6c7a6e8c37fa89307a66175ca38fd44 100644
--- a/src/main/java/org/codelibs/fess/validation/CronExpressionValidator.java
+++ b/src/main/java/org/codelibs/fess/validation/CronExpressionValidator.java
@@ -19,6 +19,7 @@ import javax.validation.ConstraintValidator;
 import javax.validation.ConstraintValidatorContext;
 
 import org.codelibs.core.lang.StringUtil;
+import org.lastaflute.job.util.LaCronUtil;
 
 public class CronExpressionValidator implements ConstraintValidator<CronExpression, String> {
 
@@ -32,7 +33,7 @@ public class CronExpressionValidator implements ConstraintValidator<CronExpressi
     }
 
     protected boolean determineValid(final String value) {
-        if (StringUtil.isNotBlank(value) && !org.quartz.CronExpression.isValidExpression(value)) {
+        if (StringUtil.isNotBlank(value) && !LaCronUtil.isCronExpValid(value)) {
             return false;
         }
         return true;
diff --git a/src/main/resources/app.xml b/src/main/resources/app.xml
index 52bfaf8e5fe3c8ba53229d5aaf64f8db43367ac1..ede9291c1b726b5329e5a1aa19d4cfaec5ee7287 100644
--- a/src/main/resources/app.xml
+++ b/src/main/resources/app.xml
@@ -4,6 +4,7 @@
 <components>
 	<include path="convention.xml"/>
 	<include path="lastaflute.xml"/>
+	<include path="lasta_job.xml"/>
 
 	<include path="fess.xml"/>
 	<include path="fess_ldap.xml"/>
diff --git a/src/main/resources/fess.xml b/src/main/resources/fess.xml
index 84a5d7f093c4e21ec8007eafde50ce5e4dab6b40..f9824fb868daf6a38ba9150e4fc887d4be6b39ba 100644
--- a/src/main/resources/fess.xml
+++ b/src/main/resources/fess.xml
@@ -18,7 +18,7 @@
 	</component>
     <component name="pathMappingHelper" class="org.codelibs.fess.helper.PathMappingHelper">
     </component>
-	<component name="jobHelper" class="org.codelibs.fess.helper.JobHelper">
+	<component name="processHelper" class="org.codelibs.fess.helper.ProcessHelper">
 	</component>
 	<component name="sambaHelper" class="org.codelibs.fess.helper.SambaHelper">
 	</component>
diff --git a/src/main/resources/fess_config.properties b/src/main/resources/fess_config.properties
index 70670f26e2b0bf3f578a1b20a1052ca17f43b720..3c804149cb41a2f22848b44889bca7a08445370d 100644
--- a/src/main/resources/fess_config.properties
+++ b/src/main/resources/fess_config.properties
@@ -222,6 +222,8 @@ mail.from.address = root@localhost
 #                                                 Scheduler
 #                                                     ------
 scheduler.target.name=
+scheduler.job.class=org.codelibs.fess.app.job.ScriptExecutorJob
+scheduler.concurrent.exec.mode=QUIT
 
 # ----------------------------------------------------------
 #                                                OnlineHelp
diff --git a/src/main/resources/fess_indices/.fess_config/scheduled_job.bulk b/src/main/resources/fess_indices/.fess_config/scheduled_job.bulk
index 877516b8168c8056b868b8e2d762fb50c50e652c..fd8ee9555af9b008f20241b0a10d9edfecd77dde 100644
--- a/src/main/resources/fess_indices/.fess_config/scheduled_job.bulk
+++ b/src/main/resources/fess_indices/.fess_config/scheduled_job.bulk
@@ -1,10 +1,10 @@
 {"index":{"_index":".fess_config","_type":"scheduled_job","_id":"default_crawler"}}
-{"name":"Default Crawler","target":"all","cronExpression":"0 0 0 * * ?","scriptType":"groovy","scriptData":"return container.getComponent(\"crawlJob\").logLevel(\"info\").execute(executor);","jobLogging":true,"crawler":true,"available":true,"sortOrder":1,"createdBy":"system","createdTime":0,"updatedBy":"system","updatedTime":0}
+{"name":"Default Crawler","target":"all","cronExpression":"0 0 * * *","scriptType":"groovy","scriptData":"return container.getComponent(\"crawlJob\").logLevel(\"info\").execute(executor);","jobLogging":true,"crawler":true,"available":true,"sortOrder":1,"createdBy":"system","createdTime":0,"updatedBy":"system","updatedTime":0}
 {"index":{"_index":".fess_config","_type":"scheduled_job","_id":"suggest_indexer"}}
-{"name":"Suggest Indexer","target":"all","cronExpression":"0 0 0 * * ?","scriptType":"groovy","scriptData":"return container.getComponent(\"suggestJob\").logLevel(\"info\").sessionId(\"SUGGEST\").execute(executor);","jobLogging":true,"crawler":false,"available":true,"sortOrder":2,"createdBy":"system","createdTime":0,"updatedBy":"system","updatedTime":0}
+{"name":"Suggest Indexer","target":"all","cronExpression":"0 0 * * *","scriptType":"groovy","scriptData":"return container.getComponent(\"suggestJob\").logLevel(\"info\").sessionId(\"SUGGEST\").execute(executor);","jobLogging":true,"crawler":false,"available":true,"sortOrder":2,"createdBy":"system","createdTime":0,"updatedBy":"system","updatedTime":0}
 {"index":{"_index":".fess_config","_type":"scheduled_job","_id":"log_aggregator"}}
-{"name":"Log Aggregator","target":"all","cronExpression":"0 * * * * ?","scriptType":"groovy","scriptData":"return container.getComponent(\"aggregateLogJob\").execute();","jobLogging":false,"crawler":false,"available":true,"sortOrder":3,"createdBy":"system","createdTime":0,"updatedBy":"system","updatedTime":0}
+{"name":"Log Aggregator","target":"all","cronExpression":"* * * * *","scriptType":"groovy","scriptData":"return container.getComponent(\"aggregateLogJob\").execute();","jobLogging":false,"crawler":false,"available":true,"sortOrder":3,"createdBy":"system","createdTime":0,"updatedBy":"system","updatedTime":0}
 {"index":{"_index":".fess_config","_type":"scheduled_job","_id":"log_purger"}}
-{"name":"Log Purger","target":"all","cronExpression":"0 0 0 * * ?","scriptType":"groovy","scriptData":"return container.getComponent(\"purgeLogJob\").execute();","jobLogging":false,"crawler":false,"available":true,"sortOrder":4,"createdBy":"system","createdTime":0,"updatedBy":"system","updatedTime":0}
+{"name":"Log Purger","target":"all","cronExpression":"0 0 * * *","scriptType":"groovy","scriptData":"return container.getComponent(\"purgeLogJob\").execute();","jobLogging":false,"crawler":false,"available":true,"sortOrder":4,"createdBy":"system","createdTime":0,"updatedBy":"system","updatedTime":0}
 {"index":{"_index":".fess_config","_type":"scheduled_job","_id":"doc_purger"}}
-{"name":"Doc Purger","target":"all","cronExpression":"0 * * * * ?","scriptType":"groovy","scriptData":"return container.getComponent(\"purgeDocJob\").execute();","jobLogging":false,"crawler":false,"available":true,"sortOrder":5,"createdBy":"system","createdTime":0,"updatedBy":"system","updatedTime":0}
+{"name":"Doc Purger","target":"all","cronExpression":"* * * * *","scriptType":"groovy","scriptData":"return container.getComponent(\"purgeDocJob\").execute();","jobLogging":false,"crawler":false,"available":true,"sortOrder":5,"createdBy":"system","createdTime":0,"updatedBy":"system","updatedTime":0}
diff --git a/src/main/resources/fess_job.xml b/src/main/resources/fess_job.xml
index 0d0040be82d620fd8efe303c6dcfe2e34d1d7846..69250538aaa2a81467ed06fa244024d2706bcb2a 100644
--- a/src/main/resources/fess_job.xml
+++ b/src/main/resources/fess_job.xml
@@ -2,8 +2,6 @@
 <!DOCTYPE components PUBLIC "-//DBFLUTE//DTD LastaDi 1.0//EN"
 	"http://dbflute.org/meta/lastadi10.dtd">
 <components>
-	<component name="jobScheduler" class="org.codelibs.fess.job.JobScheduler">
-	</component>
 	<component name="groovyJobExecutor" class="org.codelibs.fess.job.impl.GroovyExecutor" instance="prototype">
 	</component>
 
diff --git a/src/main/resources/quartz.properties b/src/main/resources/quartz.properties
deleted file mode 100644
index 3180faeaa0797498034b6da140196bd6663fcf7a..0000000000000000000000000000000000000000
--- a/src/main/resources/quartz.properties
+++ /dev/null
@@ -1,3 +0,0 @@
-org.quartz.scheduler.instanceName=JobScheduler
-org.quartz.threadPool.threadCount=5
-