All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.lontime.extquartz.impl.DefaultRedissonStorage Maven / Gradle / Ivy

There is a newer version: 1.4.0
Show newest version
package com.github.lontime.extquartz.impl;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.quartz.Calendar;
import org.quartz.CronTrigger;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.JobPersistenceException;
import org.quartz.ObjectAlreadyExistsException;
import org.quartz.SimpleTrigger;
import org.quartz.Trigger;
import org.quartz.TriggerKey;
import org.quartz.impl.JobDetailImpl;
import org.quartz.impl.matchers.GroupMatcher;
import org.quartz.impl.matchers.StringMatcher;
import org.quartz.spi.OperableTrigger;
import org.quartz.spi.SchedulerSignaler;
import org.quartz.spi.TriggerFiredBundle;
import org.quartz.spi.TriggerFiredResult;
import org.redisson.api.RBatch;
import org.redisson.api.RFuture;
import org.redisson.client.protocol.ScoredEntry;

/**
 * DefaultRedissonStorage.
 * @author lontime
 * @since 1.0
 */
public class DefaultRedissonStorage extends AbstractRedissonStorage {

    public DefaultRedissonStorage(RedissonJobStoreSchema redissonSchema, String redissonName, RedissonSerialization serialization, SchedulerSignaler signaler, String schedulerInstanceId, int lockTimeout) {
        super(redissonSchema, redissonName, serialization, signaler, schedulerInstanceId, lockTimeout);
    }

    /**
     * Store a job in Redis
     *
     * @param jobDetail       the {@link JobDetail} object to be stored
     * @param replaceExisting if true, any existing job with the same group and name as the given job will be overwritten
     * @throws ObjectAlreadyExistsException ObjectAlreadyExistsException
     */
    @SuppressWarnings("unchecked")
    @Override
    public void storeJob(JobDetail jobDetail, boolean replaceExisting) throws ObjectAlreadyExistsException {
        final String jobHashKey = redissonSchema.jobHashKey(jobDetail.getKey());
        final String jobDataMapHashKey = redissonSchema.jobDataMapHashKey(jobDetail.getKey());
        final String jobGroupSetKey = redissonSchema.jobGroupSetKey(jobDetail.getKey());

        if (!replaceExisting && redisson.getMap(jobHashKey).isExists()) {
            throw new ObjectAlreadyExistsException(jobDetail);
        }
//        if(!replaceExisting && jedis.exists(jobHashKey)){
//            throw new ObjectAlreadyExistsException(jobDetail);
//        }

        final RBatch batch = getBatch();
//        batch.getMap(jobHashKey).putAllAsync(mapper.convertValue(jobDetail, new TypeReference>() {
//        }));
        batch.getMap(jobHashKey).putAllAsync(serialization.serializeMap(jobDetail));
        batch.getMap(jobDataMapHashKey).deleteAsync();
        if (jobDetail.getJobDataMap() != null && !jobDetail.getJobDataMap().isEmpty()) {
            batch.getMap(jobDataMapHashKey).putAllAsync(getStringDataMap(jobDetail.getJobDataMap()));
        }
        batch.getSet(redissonSchema.jobsSet()).addAsync(jobHashKey);
        batch.getSet(redissonSchema.jobGroupsSet()).addAsync(jobGroupSetKey);
        batch.getSet(jobGroupSetKey).addAsync(jobHashKey);
        batch.execute();
//        Pipeline pipe = jedis.pipelined();
//        pipe.hmset(jobHashKey, (Map) mapper.convertValue(jobDetail, new TypeReference>() {}));
//        pipe.del(jobDataMapHashKey);
//        if(jobDetail.getJobDataMap() != null && !jobDetail.getJobDataMap().isEmpty()){
//            pipe.hmset(jobDataMapHashKey, getStringDataMap(jobDetail.getJobDataMap()));
//        }
//
//        pipe.sadd(redissonSchema.jobsSet(), jobHashKey);
//        pipe.sadd(redissonSchema.jobGroupsSet(), jobGroupSetKey);
//        pipe.sadd(jobGroupSetKey, jobHashKey);
//        pipe.sync();
    }

    /**
     * Remove the given job from Redis
     *
     * @param jobKey the job to be removed
     * @return true if the job was removed; false if it did not exist
     */
    @Override
    public boolean removeJob(JobKey jobKey) throws JobPersistenceException {
        final String jobHashKey = redissonSchema.jobHashKey(jobKey);
        final String jobBlockedKey = redissonSchema.jobBlockedKey(jobKey);
        final String jobDataMapHashKey = redissonSchema.jobDataMapHashKey(jobKey);
        final String jobGroupSetKey = redissonSchema.jobGroupSetKey(jobKey);
        final String jobTriggerSetKey = redissonSchema.jobTriggersSetKey(jobKey);

        final RBatch batch = getBatch();
//        Pipeline pipe = jedis.pipelined();
        // remove the job and any associated data
        final RFuture delJobHashKeyResponse = batch.getMap(jobHashKey).deleteAsync();
//        Response delJobHashKeyResponse = pipe.del(jobHashKey);
        // remove the blocked job key
        batch.getBucket(jobBlockedKey).deleteAsync();
//        pipe.del(jobBlockedKey);
        // remove the job's data map
        batch.getBucket(jobDataMapHashKey).deleteAsync();
//        pipe.del(jobDataMapHashKey);
        // remove the job from the set of all jobs
        batch.getSet(redissonSchema.jobsSet()).removeAsync(jobHashKey);
//        pipe.srem(redissonSchema.jobsSet(), jobHashKey);
        // remove the job from the set of blocked jobs
        batch.getSet(redissonSchema.blockedJobsSet()).removeAsync(jobHashKey);
//        pipe.srem(redissonSchema.blockedJobsSet(), jobHashKey);
        // remove the job from its group
        batch.getSet(jobGroupSetKey).removeAsync(jobHashKey);
//        pipe.srem(jobGroupSetKey, jobHashKey);
        // retrieve the keys for all triggers associated with this job, then delete that set
        final RFuture> jobTriggerSetResponseFuture = batch.getSet(jobTriggerSetKey).readAllAsync();
        batch.getBucket(jobTriggerSetKey).deleteAsync();
        final RFuture jobGroupSetSizeResponseFuture = batch.getSet(jobGroupSetKey).sizeAsync();
//        batch.getScript().evalAsync(RScript.Mode.READ_ONLY,
//                );
        batch.execute();
//        Response> jobTriggerSetResponse = pipe.smembers(jobTriggerSetKey);
//        pipe.del(jobTriggerSetKey);
//        Response jobGroupSetSizeResponse = pipe.scard(jobGroupSetKey);
//        pipe.sync();
//        if(jobGroupSetSizeResponse.get() == 0){
//            // The group now contains no jobs. Remove it from the set of all job groups.
//            jedis.srem(redissonSchema.jobGroupsSet(), jobGroupSetKey);
//        }
        if (jobGroupSetSizeResponseFuture.toCompletableFuture().join() == 0) {
            // The group now contains no jobs. Remove it from the set of all job groups.
            redisson.getSet(redissonSchema.jobGroupsSet()).remove(jobGroupSetKey);
//            jedis.srem(redissonSchema.jobGroupsSet(), jobGroupSetKey);
        }
//
        // remove all triggers associated with this job
//        pipe = jedis.pipelined();
        final RBatch batch1 = getBatch();
        final Set triggerHashKeys = jobTriggerSetResponseFuture.toCompletableFuture().join();
        for (String triggerHashKey : triggerHashKeys) {
            // get this trigger's TriggerKey
            final TriggerKey triggerKey = redissonSchema.triggerKey(triggerHashKey);
            final String triggerGroupSetKey = redissonSchema.triggerGroupSetKey(triggerKey);
            unsetTriggerState(triggerHashKey);
            // remove the trigger from the set of all triggers
            batch1.getSet(redissonSchema.triggersSet()).removeAsync(triggerHashKey);
            // remove the trigger's group from the set of all trigger groups
            batch1.getSet(redissonSchema.triggerGroupsSet()).removeAsync(triggerGroupSetKey);
            // remove this trigger from its group
            batch1.getSet(triggerGroupSetKey).removeAsync(triggerHashKey);
            // delete the trigger
            batch1.getMap(triggerHashKey).deleteAsync();
        }
        batch1.execute();
//        for (String triggerHashKey : jobTriggerSetResponse.get()) {
//            // get this trigger's TriggerKey
//            final TriggerKey triggerKey = redissonSchema.triggerKey(triggerHashKey);
//            final String triggerGroupSetKey = redissonSchema.triggerGroupSetKey(triggerKey);
//            unsetTriggerState(triggerHashKey);
//            // remove the trigger from the set of all triggers
//            pipe.srem(redissonSchema.triggersSet(), triggerHashKey);
//            // remove the trigger's group from the set of all trigger groups
//            pipe.srem(redissonSchema.triggerGroupsSet(), triggerGroupSetKey);
//            // remove this trigger from its group
//            pipe.srem(triggerGroupSetKey, triggerHashKey);
//            // delete the trigger
//            pipe.del(triggerHashKey);
//        }
//        pipe.sync();
//
        return delJobHashKeyResponse.toCompletableFuture().join();
    }

    /**
     * Store a trigger in redis
     *
     * @param trigger         the trigger to be stored
     * @param replaceExisting true if an existing trigger with the same identity should be replaced
     * @throws JobPersistenceException JobPersistenceException
     */
    @Override
    public void storeTrigger(OperableTrigger trigger, boolean replaceExisting) throws JobPersistenceException {
        final String triggerHashKey = redissonSchema.triggerHashKey(trigger.getKey());
        final String triggerGroupSetKey = redissonSchema.triggerGroupSetKey(trigger.getKey());
        final String jobTriggerSetKey = redissonSchema.jobTriggersSetKey(trigger.getJobKey());

        if (!(trigger instanceof SimpleTrigger) && !(trigger instanceof CronTrigger)) {
            throw new UnsupportedOperationException("Only SimpleTrigger and CronTrigger are supported.");
        }
        final boolean exists = redisson.getMap(triggerHashKey).isExists();
//        final boolean exists = jedis.exists(triggerHashKey);
        if (exists && !replaceExisting) {
            throw new ObjectAlreadyExistsException(trigger);
        }

        Map triggerMap = serialization.serializeMap(trigger);
        //mapper.convertValue(trigger, new TypeReference>() {});
        triggerMap.put(TRIGGER_CLASS, trigger.getClass().getName());

        RBatch batch = getBatch();
        batch.getMap(triggerHashKey).putAllAsync(triggerMap);
        batch.getSet(redissonSchema.triggersSet()).addAsync(triggerHashKey);
        batch.getSet(redissonSchema.triggerGroupsSet()).addAsync(triggerGroupSetKey);
        batch.getSet(triggerGroupSetKey).addAsync(triggerHashKey);
        batch.getSet(jobTriggerSetKey).addAsync(triggerHashKey);
//        Pipeline pipe = jedis.pipelined();
//        pipe.hmset(triggerHashKey, triggerMap);
//        pipe.sadd(redisSchema.triggersSet(), triggerHashKey);
//        pipe.sadd(redisSchema.triggerGroupsSet(), triggerGroupSetKey);
//        pipe.sadd(triggerGroupSetKey, triggerHashKey);
//        pipe.sadd(jobTriggerSetKey, triggerHashKey);
        if (trigger.getCalendarName() != null && !trigger.getCalendarName().isEmpty()) {
            final String calendarTriggersSetKey = redissonSchema.calendarTriggersSetKey(trigger.getCalendarName());
            batch.getSet(calendarTriggersSetKey).addAsync(triggerHashKey);
//            pipe.sadd(calendarTriggersSetKey, triggerHashKey);
        }
        if (trigger.getJobDataMap() != null && !trigger.getJobDataMap().isEmpty()) {
            final String triggerDataMapHashKey = redissonSchema.triggerDataMapHashKey(trigger.getKey());
            batch.getMap(triggerDataMapHashKey).putAllAsync(getStringDataMap(trigger.getJobDataMap()));
//            pipe.hmset(triggerDataMapHashKey, getStringDataMap(trigger.getJobDataMap()));
        }
        batch.execute();
//        pipe.sync();
//
        if (exists) {
            // We're overwriting a previously stored instance of this trigger, so clear any existing trigger state.
            unsetTriggerState(triggerHashKey);
        }

        batch = getBatch();
        final RFuture triggerPausedResponseFuture = batch.getSet(redissonSchema.pausedTriggerGroupsSet()).containsAsync(triggerGroupSetKey);
        final RFuture jobPausedResponseFuture = batch.getSet(redissonSchema.pausedJobGroupsSet()).containsAsync(redissonSchema.jobGroupSetKey(trigger.getJobKey()));
        batch.execute();
//        pipe = jedis.pipelined();
//        Response triggerPausedResponse = pipe.sismember(redisSchema.pausedTriggerGroupsSet(), triggerGroupSetKey);
//        Response jobPausedResponse = pipe.sismember(redisSchema.pausedJobGroupsSet(), redisSchema.jobGroupSetKey(trigger.getJobKey()));
//        pipe.sync();
        final String jobHashKey = redissonSchema.jobHashKey(trigger.getJobKey());
        final long nextFireTime = trigger.getNextFireTime() != null ? trigger.getNextFireTime().getTime() : -1;
        if (triggerPausedResponseFuture.toCompletableFuture().join() || jobPausedResponseFuture.toCompletableFuture().join()) {
            if (isBlockedJob(jobHashKey)) {
                setTriggerState(RedisTriggerState.PAUSED_BLOCKED, (double) nextFireTime, triggerHashKey);
            } else {
                setTriggerState(RedisTriggerState.PAUSED, (double) nextFireTime, triggerHashKey);
            }
        } else if (trigger.getNextFireTime() != null) {
            if (isBlockedJob(jobHashKey)) {
                setTriggerState(RedisTriggerState.BLOCKED, nextFireTime, triggerHashKey);
            } else {
                setTriggerState(RedisTriggerState.WAITING, (double) trigger.getNextFireTime().getTime(), triggerHashKey);
            }
        }
    }

    /**
     * Retrieve a job from redis
     *
     * @param jobKey the job key detailing the identity of the job to be retrieved
     * @return the {@link JobDetail} of the desired job
     * @throws JobPersistenceException if the desired job does not exist
     * @throws ClassNotFoundException ClassNotFoundException
     */
    @Override
    public JobDetail retrieveJob(JobKey jobKey) throws JobPersistenceException, ClassNotFoundException {
        final String jobHashKey = redissonSchema.jobHashKey(jobKey);
        final String jobDataMapHashKey = redissonSchema.jobDataMapHashKey(jobKey);

        final Map jobDetailMap = redisson.getMap(jobHashKey).readAllMap();
//        final Map jobDetailMap = jedis.hgetAll(jobHashKey);
        if (jobDetailMap == null || jobDetailMap.size() == 0) {
            // desired job does not exist
            return null;
        }
        JobDetailImpl jobDetail = serialization.deserializeMap(jobDetailMap, JobDetailImpl.class);
        //mapper.convertValue(jobDetailMap, JobDetailImpl.class);
        jobDetail.setKey(jobKey);

        final Map jobData = redisson.getMap(jobDataMapHashKey).readAllMap();
//        final Map jobData = jedis.hgetAll(jobDataMapHashKey);
        if (jobData != null && !jobData.isEmpty()) {
            JobDataMap jobDataMap = new JobDataMap();
            jobDataMap.putAll(jobData);
            jobDetail.setJobDataMap(jobDataMap);
        }

        return jobDetail;
    }

    /**
     * Check if the job identified by the given key exists in storage
     *
     * @param jobKey the key of the desired job
     * @return true if the job exists; false otherwise
     */
    @Override
    public boolean checkExists(JobKey jobKey) {
        return redisson.getMap(redissonSchema.jobHashKey(jobKey)).isExists();
//        return jedis.exists(redisSchema.jobHashKey(jobKey));
    }

    /**
     * Remove (delete) the {@link Trigger} with the given key.
     * If the associated job is non-durable and has no triggers after the given trigger is removed, the job will be
     * removed, as well.
     *
     * @param triggerKey the key of the trigger to be removed
     * @return true if the trigger was found and removed
     */
    @Override
    public boolean removeTrigger(TriggerKey triggerKey) throws JobPersistenceException, ClassNotFoundException {
        return removeTrigger(triggerKey, true);
    }

    /**
     * Remove (delete) the {@link Trigger} with the given key.
     *
     * @param triggerKey          the key of the trigger to be removed
     * @param removeNonDurableJob if true, the job associated with the given trigger will be removed if it is non-durable
     *                            and has no other triggers
     * @return true if the trigger was found and removed
     * @throws JobPersistenceException JobPersistenceException
     * @throws ClassNotFoundException ClassNotFoundException
     */
    protected boolean removeTrigger(TriggerKey triggerKey, boolean removeNonDurableJob) throws JobPersistenceException, ClassNotFoundException {
        final String triggerHashKey = redissonSchema.triggerHashKey(triggerKey);
        final String triggerGroupSetKey = redissonSchema.triggerGroupSetKey(triggerKey);

        if (!redisson.getMap(triggerHashKey).isExists()) {
            return false;
        }
//        if(!jedis.exists(triggerHashKey)){
//            return false;
//        }
//
        OperableTrigger trigger = retrieveTrigger(triggerKey);
//
        final String jobHashKey = redissonSchema.jobHashKey(trigger.getJobKey());
        final String jobTriggerSetKey = redissonSchema.jobTriggersSetKey(trigger.getJobKey());

        RBatch batch = getBatch();
//        Pipeline pipe = jedis.pipelined();
        // remove the trigger from the set of all triggers
        batch.getSet(redissonSchema.triggersSet()).removeAsync(triggerHashKey);
//        pipe.srem(redisSchema.triggersSet(), triggerHashKey);
        // remove the trigger from its trigger group set
        batch.getSet(triggerGroupSetKey).removeAsync(triggerHashKey);
//        pipe.srem(triggerGroupSetKey, triggerHashKey);
        // remove the trigger from the associated job's trigger set
        batch.getSet(jobTriggerSetKey).removeAsync(triggerHashKey);
//        pipe.srem(jobTriggerSetKey, triggerHashKey);
//        pipe.sync();
        batch.execute();

        if (redisson.getSet(triggerGroupSetKey).size() == 0) {
//        if(jedis.scard(triggerGroupSetKey) == 0){
            // The trigger group set is empty. Remove the trigger group from the set of trigger groups.
            redisson.getSet(redissonSchema.triggerGroupsSet()).remove(triggerGroupSetKey);
//            jedis.srem(redisSchema.triggerGroupsSet(), triggerGroupSetKey);
        }
//
        if (removeNonDurableJob) {
            batch = getBatch();
            final RFuture jobTriggerSetKeySizeResponseFuture = batch.getSet(jobTriggerSetKey).sizeAsync();
            final RFuture jobExistsResponseFuture = batch.getSet(jobHashKey).isExistsAsync();
            batch.execute();
            if (jobTriggerSetKeySizeResponseFuture.toCompletableFuture().join() == 0
                    && jobExistsResponseFuture.toCompletableFuture().join()) {
                JobDetail job = retrieveJob(trigger.getJobKey());
                if (!job.isDurable()) {
                    // Job is not durable and has no remaining triggers. Delete it.
                    removeJob(job.getKey());
                    signaler.notifySchedulerListenersJobDeleted(job.getKey());
                }
            }

//            pipe = jedis.pipelined();
//            Response jobTriggerSetKeySizeResponse = pipe.scard(jobTriggerSetKey);
//            Response jobExistsResponse = pipe.exists(jobHashKey);
//            pipe.sync();
//            if(jobTriggerSetKeySizeResponse.get() == 0 && jobExistsResponse.get()){
//                JobDetail job = retrieveJob(trigger.getJobKey(), jedis);
//                if(!job.isDurable()){
//                    // Job is not durable and has no remaining triggers. Delete it.
//                    removeJob(job.getKey(), jedis);
//                    signaler.notifySchedulerListenersJobDeleted(job.getKey());
//                }
//            }
        }
//
        if (isNullOrEmpty(trigger.getCalendarName())) {
            redisson.getSet(redissonSchema.calendarTriggersSetKey(trigger.getCalendarName())).remove(triggerHashKey);
//            jedis.srem(redisSchema.calendarTriggersSetKey(trigger.getCalendarName()), triggerHashKey);
        }
        unsetTriggerState(triggerHashKey);
        redisson.getMap(triggerHashKey).delete();
        redisson.getMap(redissonSchema.triggerDataMapHashKey(triggerKey)).delete();
//        jedis.del(triggerHashKey);
//        jedis.del(redisSchema.triggerDataMapHashKey(triggerKey));
        return true;
    }

    /**
     * Set a trigger state by adding the trigger to the relevant sorted set, using its next fire time as the score.
     *
     * @param state          the new state to be set
     * @param score          the trigger's next fire time
     * @param triggerHashKey the trigger hash key
     * @return true if set, false if the trigger was already a member of the given state's sorted set and its score was updated
     * @throws JobPersistenceException if the set operation fails
     */
    @Override
    public boolean setTriggerState(final RedisTriggerState state, final double score, final String triggerHashKey) throws JobPersistenceException {
        boolean success = false;
        if (state != null) {
            unsetTriggerState(triggerHashKey);
            success = redisson.getScoredSortedSet(redissonSchema.triggerStateKey(state))
                    .add(score, triggerHashKey);
//            success = jedis.zadd(redissonSchema.triggerStateKey(state), score, triggerHashKey) == 1;
        }
        return success;
    }

    /**
     * Remove (delete) the {@link Trigger} with the
     * given key, and store the new given one - which must be associated
     * with the same job.
     *
     * @param triggerKey the key of the trigger to be replaced
     * @param newTrigger the replacement trigger
     * @return true if the target trigger was found, removed, and replaced
     */
    @Override
    public boolean replaceTrigger(TriggerKey triggerKey, OperableTrigger newTrigger) throws JobPersistenceException, ClassNotFoundException {
        OperableTrigger oldTrigger = retrieveTrigger(triggerKey);
        boolean found = oldTrigger != null;
        if (found) {
            if (!oldTrigger.getJobKey().equals(newTrigger.getJobKey())) {
                throw new JobPersistenceException("New trigger is not related to the same job as the old trigger.");
            }
            removeTrigger(triggerKey, false);
            storeTrigger(newTrigger, false);
        }
        return found;
    }

    /**
     * Retrieve a trigger from Redis
     *
     * @param triggerKey the trigger key
     * @return the requested {@link OperableTrigger} if it exists; null if it does not
     * @throws JobPersistenceException if the job associated with the retrieved trigger does not exist
     */
    @Override
    public OperableTrigger retrieveTrigger(TriggerKey triggerKey) throws JobPersistenceException {
        final String triggerHashKey = redissonSchema.triggerHashKey(triggerKey);
        Map triggerMap = redisson.getMap(triggerHashKey).readAllMap();
//        Map triggerMap = jedis.hgetAll(triggerHashKey);
        if (triggerMap == null || triggerMap.isEmpty()) {
            logger.debug(String.format("No trigger exists for key %s", triggerHashKey));
            return null;
        }
        Class triggerClass;
        try {
            triggerClass = Class.forName(triggerMap.get(TRIGGER_CLASS));
        } catch (ClassNotFoundException e) {
            throw new JobPersistenceException(String.format("Could not find class %s for trigger.", triggerMap.get(TRIGGER_CLASS)), e);
        }
        triggerMap.remove(TRIGGER_CLASS);
        OperableTrigger operableTrigger = serialization.deserializeMap(triggerMap, (Class) triggerClass);
        //(OperableTrigger) mapper.convertValue(triggerMap, triggerClass);
        operableTrigger.setFireInstanceId(schedulerInstanceId + "-" + operableTrigger.getKey() + "-" + operableTrigger.getStartTime().getTime());
        final Map jobData = redisson.getMap(redissonSchema.triggerDataMapHashKey(triggerKey)).readAllMap();
//        final Map jobData = jedis.hgetAll(redisSchema.triggerDataMapHashKey(triggerKey));
        if (jobData != null && !jobData.isEmpty()) {
            JobDataMap jobDataMap = new JobDataMap();
            jobDataMap.putAll(jobData);
            operableTrigger.setJobDataMap(jobDataMap);
        }
        return operableTrigger;
    }

    /**
     * Unsets the state of the given trigger key by removing the trigger from all trigger state sets.
     *
     * @param triggerHashKey the redis key of the desired trigger hash
     * @return true if the trigger was removed, false if the trigger was stateless
     * @throws JobPersistenceException if the unset operation failed
     */
    @Override
    public boolean unsetTriggerState(final String triggerHashKey) throws JobPersistenceException {
        boolean removed = false;
        final RBatch batch = getBatch();
//        Pipeline pipe = jedis.pipelined();
        List> responses = new ArrayList<>(RedisTriggerState.values().length);
        for (RedisTriggerState state : RedisTriggerState.values()) {
            responses.add(batch.getScoredSortedSet(redissonSchema.triggerStateKey(state)).removeAsync(triggerHashKey));
//            responses.add(pipe.zrem(redisSchema.triggerStateKey(state), triggerHashKey));
        }
        batch.execute();
        for (RFuture response : responses) {
            removed = response.toCompletableFuture().join();
            if (removed) {
                redisson.getBucket(redissonSchema.triggerLockKey(redissonSchema.triggerKey(triggerHashKey))).delete();
                break;
            }
        }
//        pipe.sync();
//        for (Response response : responses) {
//            removed = response.get() == 1;
//            if(removed){
//                jedis.del(redisSchema.triggerLockKey(redisSchema.triggerKey(triggerHashKey)));
//                break;
//            }
//        }
        return removed;
    }

    /**
     * Check if the trigger identified by the given key exists
     *
     * @param triggerKey the key of the desired trigger
     * @return true if the trigger exists; false otherwise
     */
    @Override
    public boolean checkExists(TriggerKey triggerKey) {
        return redisson.getMap(redissonSchema.triggerHashKey(triggerKey)).isExists();
//        return jedis.exists(redisSchema.triggerHashKey(triggerKey));
    }

    /**
     * Clear (delete!) all scheduling data - all {@link Job}s, {@link Trigger}s {@link Calendar}s.
     */
    @Override
    public void clearAllSchedulingData() throws JobPersistenceException, ClassNotFoundException {
        // delete triggers
        final Set jobHashKeys = redisson.getSet(redissonSchema.jobsSet()).readAll();
        for (String jobHashKey : jobHashKeys) {
            removeJob(redissonSchema.jobKey(jobHashKey));
        }

        // delete remaining jobs
        final Set triggerHashKeys = redisson.getSet(redissonSchema.triggersSet()).readAll();
        for (String triggerHashKey : triggerHashKeys) {
            removeTrigger(redissonSchema.triggerKey(triggerHashKey));
        }

        // remove calendars
        final Set calendarHashKeys = redisson.getSet(redissonSchema.calendarsSet()).readAll();
        for (String calendarHashKey : calendarHashKeys) {
            removeCalendar(redissonSchema.calendarName(calendarHashKey));
        }
    }

    /**
     * Store a {@link Calendar}
     *
     * @param name            the name of the calendar
     * @param calendar        the calendar object to be stored
     * @param replaceExisting if true, any existing calendar with the same name will be overwritten
     * @param updateTriggers  if true, any existing triggers associated with the calendar will be updated
     * @throws JobPersistenceException JobPersistenceException
     */
    @Override
    public void storeCalendar(String name, Calendar calendar, boolean replaceExisting, boolean updateTriggers) throws JobPersistenceException {
        final String calendarHashKey = redissonSchema.calendarHashKey(name);
        if (!replaceExisting && redisson.getMap(calendarHashKey).isExists()) {
            throw new ObjectAlreadyExistsException(String.format("Calendar with key %s already exists.", calendarHashKey));
        }
        Map calendarMap = new HashMap<>();
        calendarMap.put(CALENDAR_CLASS, calendar.getClass().getName());
//        try {
//            calendarMap.put(CALENDAR_JSON, mapper.writeValueAsString(calendar));
//        } catch (JsonProcessingException e) {
//            throw new JobPersistenceException("Unable to serialize calendar.", e);
//        }
        calendarMap.put(CALENDAR_JSON, serialization.writeValueAsString(calendar));

        final RBatch batch = getBatch();
        batch.getMap(calendarHashKey).putAllAsync(calendarMap);
        batch.getSet(redissonSchema.calendarsSet()).addAsync(calendarHashKey);
        batch.execute();
//        Pipeline pipe = jedis.pipelined();
//        pipe.hmset(calendarHashKey, calendarMap);
//        pipe.sadd(redisSchema.calendarsSet(), calendarHashKey);
//        pipe.sync();
//
        if (updateTriggers) {
            final String calendarTriggersSetKey = redissonSchema.calendarTriggersSetKey(name);
            final Set triggerHashKeys = redisson.getSet(calendarTriggersSetKey).readAll();
//            Set triggerHashKeys = jedis.smembers(calendarTriggersSetKey);
            for (String triggerHashKey : triggerHashKeys) {
                OperableTrigger trigger = retrieveTrigger(redissonSchema.triggerKey(triggerHashKey));
                boolean removed = redisson.getScoredSortedSet(redissonSchema.triggerStateKey(RedisTriggerState.WAITING)).remove(triggerHashKey);
//                long removed = jedis.zrem(redisSchema.triggerStateKey(RedisTriggerState.WAITING), triggerHashKey);
                trigger.updateWithNewCalendar(calendar, misfireThreshold);
                if (removed) {
                    setTriggerState(RedisTriggerState.WAITING, (double) trigger.getNextFireTime().getTime(), triggerHashKey);
                }
            }
        }
    }

    /**
     * Remove (delete) the {@link Calendar} with the given name.
     *
     * @param calendarName the name of the calendar to be removed
     * @return true if a calendar with the given name was found and removed
     */
    @Override
    public boolean removeCalendar(String calendarName) throws JobPersistenceException {
        final String calendarTriggersSetKey = redissonSchema.calendarTriggersSetKey(calendarName);

        if (redisson.getSet(calendarTriggersSetKey).size() > 0) {
//        if(jedis.scard(calendarTriggersSetKey) > 0){
            throw new JobPersistenceException(String.format("There are triggers pointing to calendar %s, so it cannot be removed.", calendarName));
        }
        final String calendarHashKey = redissonSchema.calendarHashKey(calendarName);
        final RBatch batch = getBatch();
        final RFuture deleteResponseFuture = batch.getMap(calendarHashKey).deleteAsync();
        batch.getSet(redissonSchema.calendarsSet()).removeAsync(calendarHashKey);
        batch.execute();
//        Pipeline pipe = jedis.pipelined();
//        Response deleteResponse = pipe.del(calendarHashKey);
//        pipe.srem(redisSchema.calendarsSet(), calendarHashKey);
//        pipe.sync();
//
        return deleteResponseFuture.toCompletableFuture().join();
    }

    /**
     * Retrieve a calendar
     *
     * @param name the name of the calendar to be retrieved
     * @return the desired calendar if it exists; null otherwise
     */
    @Override
    @SuppressWarnings("all")
    public Calendar retrieveCalendar(String name) throws JobPersistenceException {
        final String calendarHashKey = redissonSchema.calendarHashKey(name);
        Calendar calendar;
        try {
//            final Map calendarMap = jedis.hgetAll(calendarHashKey);
            final Map calendarMap = redisson.getMap(calendarHashKey).readAllMap();
            if (calendarMap == null || calendarMap.isEmpty()) {
                return null;
            }
            final Class calendarClass = Class.forName(calendarMap.get(CALENDAR_CLASS));
            calendar = serialization.readValue(calendarMap.get(CALENDAR_JSON), (Class) calendarClass);
            //(Calendar) mapper.readValue(calendarMap.get(CALENDAR_JSON), calendarClass);
        } catch (ClassNotFoundException e) {
            logger.error("Class not found for calendar " + name);
            throw new JobPersistenceException(e.getMessage(), e);
        }
//        catch (IOException e) {
//            logger.error("Unable to deserialize calendar json for calendar " + name);
//            throw new JobPersistenceException(e.getMessage(), e);
//        }
        return calendar;
    }

    /**
     * Get the number of stored jobs
     *
     * @return the number of jobs currently persisted in the jobstore
     */
    @Override
    public int getNumberOfJobs() {
        return redisson.getSet(redissonSchema.jobsSet()).size();
//        return jedis.scard(redisSchema.jobsSet()).intValue();
    }

    /**
     * Get the number of stored triggers
     *
     * @return the number of triggers currently persisted in the jobstore
     */
    @Override
    public int getNumberOfTriggers() {
        return redisson.getSet(redissonSchema.triggersSet()).size();
//        return jedis.scard(redisSchema.triggersSet()).intValue();
    }

    /**
     * Get the number of stored calendars
     *
     * @return the number of calendars currently persisted in the jobstore
     */
    @Override
    public int getNumberOfCalendars() {
        return redisson.getSet(redissonSchema.calendarsSet()).size();
//        return jedis.scard(redisSchema.calendarsSet()).intValue();
    }

    /**
     * Get the keys of all of the {@link Job} s that have the given group name.
     *
     * @param matcher the matcher with which to compare group names
     * @return the set of all JobKeys which have the given group name
     */
    @Override
    public Set getJobKeys(GroupMatcher matcher) {
        Set jobKeys = new HashSet<>();
        if (matcher.getCompareWithOperator() == StringMatcher.StringOperatorName.EQUALS) {
            final String jobGroupSetKey = redissonSchema.jobGroupSetKey(new JobKey("", matcher.getCompareToValue()));
            final Set jobs = redisson.getSet(jobGroupSetKey).readAll();
//            final Set jobs = jedis.smembers(jobGroupSetKey);
            if (jobs != null) {
                for (final String job : jobs) {
                    jobKeys.add(redissonSchema.jobKey(job));
                }
            }
        } else {
            List>> jobGroups = new ArrayList<>();
//            Pipeline pipe = jedis.pipelined();
            final RBatch batch = getBatch();
            final Set jobGroupSetKeys = redisson.getSet(redissonSchema.jobGroupsSet()).readAll();
            for (final String jobGroupSetKey : jobGroupSetKeys) {
                if (matcher.getCompareWithOperator().evaluate(redissonSchema.jobGroup(jobGroupSetKey), matcher.getCompareToValue())) {
                    jobGroups.add(batch.getSet(jobGroupSetKey).readAllAsync());
//                    jobGroups.add(pipe.smembers(jobGroupSetKey));
                }
            }
            batch.execute();
//            pipe.sync();
            for (RFuture> jobGroup : jobGroups) {
                final Set jobs = jobGroup.toCompletableFuture().join();
                if (jobs != null) {
                    for (final String job : jobs) {
                        jobKeys.add(redissonSchema.jobKey(job));
                    }
                }
            }
        }
        return jobKeys;
    }

    /**
     * Get the names of all of the {@link Trigger} s that have the given group name.
     *
     * @param matcher the matcher with which to compare group names
     * @return the set of all TriggerKeys which have the given group name
     */
    @Override
    public Set getTriggerKeys(GroupMatcher matcher) {
        Set triggerKeys = new HashSet<>();
        if (matcher.getCompareWithOperator() == StringMatcher.StringOperatorName.EQUALS) {
            final String triggerGroupSetKey = redissonSchema.triggerGroupSetKey(new TriggerKey("", matcher.getCompareToValue()));
            final Set triggers = redisson.getSet(triggerGroupSetKey).readAll();
//            final Set triggers = jedis.smembers(triggerGroupSetKey);
            if (triggers != null) {
                for (final String trigger : triggers) {
                    triggerKeys.add(redissonSchema.triggerKey(trigger));
                }
            }
        } else {
            List>> triggerGroups = new ArrayList<>();
            final RBatch batch = getBatch();
//            Pipeline pipe = jedis.pipelined();
            final Set triggerGroupSetKeys = redisson.getSet(redissonSchema.triggerGroupsSet()).readAll();
            for (final String triggerGroupSetKey : triggerGroupSetKeys) {
                if (matcher.getCompareWithOperator().evaluate(redissonSchema.triggerGroup(triggerGroupSetKey), matcher.getCompareToValue())) {
                    triggerGroups.add(batch.getSet(triggerGroupSetKey).readAllAsync());
//                    triggerGroups.add(pipe.smembers(triggerGroupSetKey));
                }
            }
            batch.execute();
//            pipe.sync();
            for (RFuture> triggerGroup : triggerGroups) {
                final Set triggers = triggerGroup.toCompletableFuture().join();
                if (triggers != null) {
                    for (final String trigger : triggers) {
                        triggerKeys.add(redissonSchema.triggerKey(trigger));
                    }
                }
            }
        }
        return triggerKeys;
    }

    /**
     * Get the names of all of the {@link Job} groups.
     *
     * @return the names of all of the job groups or an empty list if no job groups exist
     */
    @Override
    public List getJobGroupNames() {
        final Set groupsSet = redisson.getSet(redissonSchema.jobGroupsSet()).readAll();
//        final Set groupsSet = jedis.smembers(redisSchema.jobGroupsSet());
        List groups = new ArrayList<>(groupsSet.size());
        for (String group : groupsSet) {
            groups.add(redissonSchema.jobGroup(group));
        }
        return groups;
    }

    /**
     * Get the names of all of the {@link Trigger} groups.
     *
     * @return the names of all trigger groups or an empty list if no trigger groups exist
     */
    @Override
    public List getTriggerGroupNames() {
        final Set groupsSet = redisson.getSet(redissonSchema.triggerGroupsSet()).readAll();
//        final Set groupsSet = jedis.smembers(redisSchema.triggerGroupsSet());
        List groups = new ArrayList<>(groupsSet.size());
        for (String group : groupsSet) {
            groups.add(redissonSchema.triggerGroup(group));
        }
        return groups;
    }

    /**
     * Get the names of all of the {@link Calendar} s in the JobStore.
     *
     * @return the names of all calendars or an empty list if no calendars exist
     */
    @Override
    public List getCalendarNames() {
        final Set calendarsSet = redisson.getSet(redissonSchema.calendarsSet()).readAll();
//        final Set calendarsSet = jedis.smembers(redisSchema.calendarsSet());
        List calendars = new ArrayList<>(calendarsSet.size());
        for (String group : calendarsSet) {
            calendars.add(redissonSchema.calendarName(group));
        }
        return calendars;
    }

    /**
     * Retrieve triggers associated with the given job
     *
     * @param jobKey the job for which to retrieve triggers
     * @return a list of triggers associated with the given job
     */
    @Override
    public List getTriggersForJob(JobKey jobKey) throws JobPersistenceException {
        final String jobTriggerSetKey = redissonSchema.jobTriggersSetKey(jobKey);
        final Set triggerHashKeys = redisson.getSet(jobTriggerSetKey).readAll();
//        final Set triggerHashKeys = jedis.smembers(jobTriggerSetKey);
        List triggers = new ArrayList<>();
        for (String triggerHashKey : triggerHashKeys) {
            triggers.add(retrieveTrigger(redissonSchema.triggerKey(triggerHashKey)));
        }
        return triggers;
    }

    /**
     * Get the current state of the identified {@link Trigger}.
     *
     * @param triggerKey the key of the desired trigger
     * @return the state of the trigger
     */
    @Override
    public Trigger.TriggerState getTriggerState(TriggerKey triggerKey) {
        final String triggerHashKey = redissonSchema.triggerHashKey(triggerKey);
        final RBatch batch = getBatch();
//        Pipeline pipe = jedis.pipelined();
        Map> scores = new HashMap<>(RedisTriggerState.values().length);
        for (RedisTriggerState redisTriggerState : RedisTriggerState.values()) {
            scores.put(redisTriggerState, batch.getScoredSortedSet(redissonSchema.triggerStateKey(redisTriggerState)).getScoreAsync(triggerHashKey));
//            scores.put(redisTriggerState, pipe.zscore(redisSchema.triggerStateKey(redisTriggerState), triggerHashKey));
        }
        batch.execute();
//        pipe.sync();
        for (Map.Entry> entry : scores.entrySet()) {
            if (entry.getValue().toCompletableFuture().join() != null) {
                return entry.getKey().getTriggerState();
            }
        }
        return Trigger.TriggerState.NONE;
    }

    /**
     * Pause the trigger with the given key
     *
     * @param triggerKey the key of the trigger to be paused
     * @throws JobPersistenceException if the desired trigger does not exist
     */
    @Override
    public void pauseTrigger(TriggerKey triggerKey) throws JobPersistenceException {
        final String triggerHashKey = redissonSchema.triggerHashKey(triggerKey);
        final RBatch batch = getBatch();
//        Pipeline pipe = jedis.pipelined();
        final RFuture exists = batch.getMap(triggerHashKey).isExistsAsync();
        final RFuture completedScore = batch.getScoredSortedSet(redissonSchema.triggerStateKey(RedisTriggerState.COMPLETED)).getScoreAsync(triggerHashKey);
        final RFuture nextFireTimeResponse = batch.getMap(triggerHashKey).getAsync(TRIGGER_NEXT_FIRE_TIME);
        final RFuture blockedScore = batch.getScoredSortedSet(redissonSchema.triggerStateKey(RedisTriggerState.BLOCKED)).getScoreAsync(triggerHashKey);
        batch.execute();
//        Response exists = pipe.exists(triggerHashKey);
//        Response completedScore = pipe.zscore(redisSchema.triggerStateKey(RedisTriggerState.COMPLETED), triggerHashKey);
//        Response nextFireTimeResponse = pipe.hget(triggerHashKey, TRIGGER_NEXT_FIRE_TIME);
//        Response blockedScore = pipe.zscore(redisSchema.triggerStateKey(RedisTriggerState.BLOCKED), triggerHashKey);
//        pipe.sync();
//
        if (!exists.toCompletableFuture().join()) {
            return;
        }
        if (completedScore.toCompletableFuture().join() != null) {
            // doesn't make sense to pause a completed trigger
            return;
        }

        final long nextFireTime = nextFireTimeResponse.toCompletableFuture().join() == null
                || nextFireTimeResponse.toCompletableFuture().join().isEmpty() ? -1 : Long.parseLong(nextFireTimeResponse.toCompletableFuture().join());
        if (blockedScore.toCompletableFuture().join() != null) {
            setTriggerState(RedisTriggerState.PAUSED_BLOCKED, (double) nextFireTime, triggerHashKey);
        } else {
            setTriggerState(RedisTriggerState.PAUSED, (double) nextFireTime, triggerHashKey);
        }
    }

    /**
     * Pause all of the {@link Trigger}s in the given group.
     *
     * @param matcher matcher for the trigger groups to be paused
     * @return a collection of names of trigger groups which were matched and paused
     * @throws JobPersistenceException JobPersistenceException
     */
    @Override
    public Collection pauseTriggers(GroupMatcher matcher) throws JobPersistenceException {
        Set pausedTriggerGroups = new HashSet<>();
        if (matcher.getCompareWithOperator() == StringMatcher.StringOperatorName.EQUALS) {
            final String triggerGroupSetKey = redissonSchema.triggerGroupSetKey(new TriggerKey("", matcher.getCompareToValue()));
            final boolean addResult = redisson.getSet(redissonSchema.pausedTriggerGroupsSet()).add(triggerGroupSetKey);
//            final long addResult = jedis.sadd(redisSchema.pausedTriggerGroupsSet(), triggerGroupSetKey);
            if (addResult) {
                final Set triggers = redisson.getSet(triggerGroupSetKey).readAll();
                for (final String trigger : triggers) {
                    pauseTrigger(redissonSchema.triggerKey(trigger));
                }
                pausedTriggerGroups.add(redissonSchema.triggerGroup(triggerGroupSetKey));
            }
        } else {
            Map>> triggerGroups = new HashMap<>();
            final RBatch batch = getBatch();
            final Set triggerGroupSetKeys = redisson.getSet(redissonSchema.triggerGroupsSet()).readAll();
//            Pipeline pipe = jedis.pipelined();
            for (final String triggerGroupSetKey : triggerGroupSetKeys) {
                if (matcher.getCompareWithOperator().evaluate(redissonSchema.triggerGroup(triggerGroupSetKey), matcher.getCompareToValue())) {
                    triggerGroups.put(triggerGroupSetKey, batch.getSet(redissonSchema.triggerGroupsSet()).readAllAsync());
                }
            }
            batch.execute();
//            pipe.sync();
            for (final Map.Entry>> entry : triggerGroups.entrySet()) {
                if (redisson.getSet(redissonSchema.pausedJobGroupsSet()).add(entry.getKey())) {
//                if(jedis.sadd(redisSchema.pausedJobGroupsSet(), entry.getKey()) > 0){
                    // This trigger group was not paused. Pause it now.
                    pausedTriggerGroups.add(redissonSchema.triggerGroup(entry.getKey()));
                    for (final String triggerHashKey : entry.getValue().toCompletableFuture().join()) {
                        pauseTrigger(redissonSchema.triggerKey(triggerHashKey));
                    }
                }
            }
        }
        return pausedTriggerGroups;
    }

    /**
     * Pause a job by pausing all of its triggers
     *
     * @param jobKey the key of the job to be paused
     */
    @Override
    public void pauseJob(JobKey jobKey) throws JobPersistenceException {
        for (OperableTrigger trigger : getTriggersForJob(jobKey)) {
            pauseTrigger(trigger.getKey());
        }
    }

    /**
     * Pause all of the {@link Job}s in the given group - by pausing all of their
     * Triggers.
     *
     * @param groupMatcher the mather which will determine which job group should be paused
     * @return a collection of names of job groups which have been paused
     * @throws JobPersistenceException JobPersistenceException
     */
    @Override
    public Collection pauseJobs(GroupMatcher groupMatcher) throws JobPersistenceException {
        Set pausedJobGroups = new HashSet<>();
        if (groupMatcher.getCompareWithOperator() == StringMatcher.StringOperatorName.EQUALS) {
            final String jobGroupSetKey = redissonSchema.jobGroupSetKey(new JobKey("", groupMatcher.getCompareToValue()));
            if (redisson.getSet(redissonSchema.pausedJobGroupsSet()).add(jobGroupSetKey)) {
//            if(jedis.sadd(redissonSchema.pausedJobGroupsSet(), jobGroupSetKey) > 0){
                pausedJobGroups.add(redissonSchema.jobGroup(jobGroupSetKey));
                final Set jobs = redisson.getSet(jobGroupSetKey).readAll();
                for (String job : jobs) {
                    pauseJob(redissonSchema.jobKey(job));
                }
            }
        } else {
            Map>> jobGroups = new HashMap<>();
//            Pipeline pipe = jedis.pipelined();
            final RBatch batch = getBatch();
            final Set jobGroupSetKeys = redisson.getSet(redissonSchema.jobGroupsSet()).readAll();
            for (final String jobGroupSetKey : jobGroupSetKeys) {
                if (groupMatcher.getCompareWithOperator().evaluate(redissonSchema.jobGroup(jobGroupSetKey), groupMatcher.getCompareToValue())) {
                    jobGroups.put(jobGroupSetKey, batch.getSet(jobGroupSetKey).readAllAsync());
//                    jobGroups.put(jobGroupSetKey, pipe.smembers(jobGroupSetKey));
                }
            }
            batch.execute();
//            pipe.sync();
            for (final Map.Entry>> entry : jobGroups.entrySet()) {
                if (redisson.getSet(redissonSchema.pausedJobGroupsSet()).add(entry.getKey())) {
//                if(jedis.sadd(redissonSchema.pausedJobGroupsSet(), entry.getKey()) > 0){
                    // This job group was not already paused. Pause it now.
                    pausedJobGroups.add(redissonSchema.jobGroup(entry.getKey()));
                    for (final String jobHashKey : entry.getValue().toCompletableFuture().join()) {
                        pauseJob(redissonSchema.jobKey(jobHashKey));
                    }
                }
            }
        }
        return pausedJobGroups;
    }

    /**
     * Resume (un-pause) a {@link Trigger}
     *
     * @param triggerKey the key of the trigger to be resumed
     */
    @Override
    public void resumeTrigger(TriggerKey triggerKey) throws JobPersistenceException {
        final String triggerHashKey = redissonSchema.triggerHashKey(triggerKey);
        final RBatch batch = getBatch();
        final RFuture exists = batch.getSet(redissonSchema.triggersSet()).containsAsync(triggerHashKey);
        RFuture isPaused = batch.getScoredSortedSet(redissonSchema.triggerStateKey(RedisTriggerState.PAUSED)).getScoreAsync(triggerHashKey);
        RFuture isPausedBlocked = batch.getScoredSortedSet(redissonSchema.triggerStateKey(RedisTriggerState.PAUSED_BLOCKED)).getScoreAsync(triggerHashKey);
        batch.execute();
//        Pipeline pipe = jedis.pipelined();
//        Response exists = pipe.sismember(redisSchema.triggersSet(), triggerHashKey);
//        Response isPaused = pipe.zscore(redisSchema.triggerStateKey(RedisTriggerState.PAUSED), triggerHashKey);
//        Response isPausedBlocked = pipe.zscore(redisSchema.triggerStateKey(RedisTriggerState.PAUSED_BLOCKED), triggerHashKey);
//        pipe.sync();
//
        if (!exists.toCompletableFuture().join()) {
            // Trigger does not exist.  Nothing to do.
            return;
        }
        if (isPaused.toCompletableFuture().join() == null && isPausedBlocked.toCompletableFuture().join() == null) {
            // Trigger is not paused. Nothing to do.
            return;
        }
        OperableTrigger trigger = retrieveTrigger(triggerKey);
        final String jobHashKey = redissonSchema.jobHashKey(trigger.getJobKey());
        final Date nextFireTime = trigger.getNextFireTime();

        if (nextFireTime != null) {
            if (isBlockedJob(jobHashKey)) {
                setTriggerState(RedisTriggerState.BLOCKED, (double) nextFireTime.getTime(), triggerHashKey);
            } else {
                setTriggerState(RedisTriggerState.WAITING, (double) nextFireTime.getTime(), triggerHashKey);
            }
        }
        applyMisfire(trigger);
    }

    /**
     * Resume (un-pause) all of the {@link Trigger}s in the given group.
     *
     * @param matcher matcher for the trigger groups to be resumed
     * @return the names of trigger groups which were resumed
     */
    @Override
    public Collection resumeTriggers(GroupMatcher matcher) throws JobPersistenceException {
        Set resumedTriggerGroups = new HashSet<>();
        if (matcher.getCompareWithOperator() == StringMatcher.StringOperatorName.EQUALS) {
            final String triggerGroupSetKey = redissonSchema.triggerGroupSetKey(new TriggerKey("", matcher.getCompareToValue()));
            final RBatch batch = getBatch();
//            Pipeline pipe = jedis.pipelined();
            batch.getSet(redissonSchema.pausedJobGroupsSet()).removeAsync(triggerGroupSetKey);
//            pipe.srem(redissonSchema.pausedJobGroupsSet(), triggerGroupSetKey);
            final RFuture> triggerHashKeysResponse = batch.getSet(triggerGroupSetKey).readAllAsync();
//            Response> triggerHashKeysResponse = pipe.smembers(triggerGroupSetKey);
//            pipe.sync();
            batch.execute();
            for (String triggerHashKey : triggerHashKeysResponse.toCompletableFuture().join()) {
                OperableTrigger trigger = retrieveTrigger(redissonSchema.triggerKey(triggerHashKey));
                resumeTrigger(trigger.getKey());
                resumedTriggerGroups.add(trigger.getKey().getGroup());
            }
        } else {
            final Set triggerGroupSetKeys = redisson.getSet(redissonSchema.triggerGroupsSet()).readAll();
            for (final String triggerGroupSetKey : triggerGroupSetKeys) {
                if (matcher.getCompareWithOperator().evaluate(redissonSchema.triggerGroup(triggerGroupSetKey), matcher.getCompareToValue())) {
                    resumedTriggerGroups.addAll(resumeTriggers(GroupMatcher.triggerGroupEquals(redissonSchema.triggerGroup(triggerGroupSetKey))));
                }
            }
        }
        return resumedTriggerGroups;
    }

    /**
     * Retrieve all currently paused trigger groups
     *
     * @return a set containing the names of all currently paused trigger groups
     */
    @Override
    public Set getPausedTriggerGroups() {
        final Set triggerGroupSetKeys = redisson.getSet(redissonSchema.pausedTriggerGroupsSet()).readAll();
//        final Set triggerGroupSetKeys = jedis.smembers(redisSchema.pausedTriggerGroupsSet());
        Set names = new HashSet<>(triggerGroupSetKeys.size());
        for (String triggerGroupSetKey : triggerGroupSetKeys) {
            names.add(redissonSchema.triggerGroup(triggerGroupSetKey));
        }
        return triggerGroupSetKeys;
    }

    /**
     * Resume (un-pause) the {@link Job} with the given key.
     *
     * @param jobKey the key of the job to be resumed
     */
    @Override
    public void resumeJob(JobKey jobKey) throws JobPersistenceException {
        for (OperableTrigger trigger : getTriggersForJob(jobKey)) {
            resumeTrigger(trigger.getKey());
        }
    }

    /**
     * Resume (un-pause) all of the {@link Job}s in the given group.
     *
     * @param matcher the matcher with which to compare job group names
     * @return the set of job groups which were matched and resumed
     */
    @Override
    public Collection resumeJobs(GroupMatcher matcher) throws JobPersistenceException {
        Set resumedJobGroups = new HashSet<>();
        if (matcher.getCompareWithOperator() == StringMatcher.StringOperatorName.EQUALS) {
            final String jobGroupSetKey = redissonSchema.jobGroupSetKey(new JobKey("", matcher.getCompareToValue()));
            final RBatch batch = getBatch();
//            Pipeline pipe = jedis.pipelined();
            final RFuture unpauseResponse = batch.getSet(redissonSchema.pausedJobGroupsSet()).removeAsync(jobGroupSetKey);
//            Response unpauseResponse = pipe.srem(redisSchema.pausedJobGroupsSet(), jobGroupSetKey);
            final RFuture> jobsResponse = batch.getSet(jobGroupSetKey).readAllAsync();
//            Response> jobsResponse = pipe.smembers(jobGroupSetKey);
//            pipe.sync();
            batch.execute();
            if (unpauseResponse.toCompletableFuture().join()) {
                resumedJobGroups.add(redissonSchema.jobGroup(jobGroupSetKey));
            }
            for (String job : jobsResponse.toCompletableFuture().join()) {
                resumeJob(redissonSchema.jobKey(job));
            }
        } else {
            final Set jobGroupSetKeys = redisson.getSet(redissonSchema.jobGroupsSet()).readAll();
            for (final String jobGroupSetKey : jobGroupSetKeys) {
                if (matcher.getCompareWithOperator().evaluate(redissonSchema.jobGroup(jobGroupSetKey), matcher.getCompareToValue())) {
                    resumedJobGroups.addAll(resumeJobs(GroupMatcher.jobGroupEquals(redissonSchema.jobGroup(jobGroupSetKey))));
                }
            }
        }
        return resumedJobGroups;
    }

    /**
     * Pause all triggers - equivalent of calling pauseTriggerGroup(group) on every group.
     */
    @Override
    public void pauseAll() throws JobPersistenceException {
        final Set triggerGroupSets = redisson.getSet(redissonSchema.triggerGroupsSet()).readAll();
        for (String triggerGroupSet : triggerGroupSets) {
            pauseTriggers(GroupMatcher.triggerGroupEquals(redissonSchema.triggerGroup(triggerGroupSet)));
        }
    }

    /**
     * Resume (un-pause) all triggers - equivalent of calling resumeTriggerGroup(group) on every group.
     */
    @Override
    public void resumeAll() throws JobPersistenceException {
        final Set triggerGroupSets = redisson.getSet(redissonSchema.triggerGroupsSet()).readAll();
        for (String triggerGroupSet : triggerGroupSets) {
            resumeTriggers(GroupMatcher.triggerGroupEquals(redissonSchema.triggerGroup(triggerGroupSet)));
        }
    }

    /**
     * Get a handle to the next trigger to be fired, and mark it as 'reserved'
     * by the calling scheduler.
     *
     * @param noLaterThan If > 0, the JobStore should only return a Trigger
     *                    that will fire no later than the time represented in this value as
     *                    milliseconds.
     * @param maxCount    the maximum number of triggers to return
     * @param timeWindow  the time window within which the triggers must fire next
     * @return the acquired triggers
     * @throws JobPersistenceException JobPersistenceException
     * @throws ClassNotFoundException ClassNotFoundException
     */
    @Override
    public List acquireNextTriggers(long noLaterThan, int maxCount, long timeWindow) throws JobPersistenceException, ClassNotFoundException {
        releaseTriggersCron();
        setLastInstanceActiveTime(schedulerInstanceId, System.currentTimeMillis());
        List acquiredTriggers = new ArrayList<>();
        boolean retry;
        do {
            retry = false;
            Set acquiredJobHashKeysForNoConcurrentExec = new HashSet<>();
            if (logger.isTraceEnabled()) {
                logger.trace("Current time is {}. Attempting to acquire triggers firing no later than {}", System.currentTimeMillis(), (noLaterThan + timeWindow));
            }
            final Collection> triggerTuples = redisson.getScoredSortedSet(redissonSchema.triggerStateKey(RedisTriggerState.WAITING))
                    .entryRange(0, true, (double) (noLaterThan + timeWindow), true, 0, maxCount);
            for (ScoredEntry triggerTuple : triggerTuples) {
//            for (Tuple triggerTuple : jedis.zrangeByScoreWithScores(redissonSchema.triggerStateKey(RedisTriggerState.WAITING), 0, (double) (noLaterThan + timeWindow), 0, maxCount)) {
                OperableTrigger trigger = retrieveTrigger(redissonSchema.triggerKey(triggerTuple.getValue()));
                if (applyMisfire(trigger)) {
                    if (logger.isDebugEnabled()) {
                        logger.debug("misfired trigger: " + triggerTuple.getValue());
                    }
                    retry = true;
                    break;
                }
                if (trigger.getNextFireTime() == null) {
                    // Trigger has no next fire time. Unset its WAITING state.
                    unsetTriggerState(triggerTuple.getValue());
                    continue;
                }
                final String jobHashKey = redissonSchema.jobHashKey(trigger.getJobKey());
                JobDetail job = retrieveJob(trigger.getJobKey());
                if (job != null && isJobConcurrentExecutionDisallowed(job.getJobClass())) {
                    if (logger.isTraceEnabled()) {
                        logger.trace("Attempting to acquire job " + job.getKey() + " with concurrent execution disallowed.");
                    }
                    if (acquiredJobHashKeysForNoConcurrentExec.contains(jobHashKey)) {
                        // a trigger is already acquired for this job
                        if (logger.isTraceEnabled()) {
                            logger.trace("Job " + job.getKey() + " with concurrent execution disallowed already acquired.");
                        }
                        continue;
                    } else {
                        if (logger.isTraceEnabled()) {
                            logger.trace("Job " + job.getKey() + " with concurrent execution disallowed not yet acquired. Acquiring.");
                        }
                        acquiredJobHashKeysForNoConcurrentExec.add(jobHashKey);
                    }
                }
                // acquire the trigger
                setTriggerState(RedisTriggerState.ACQUIRED, triggerTuple.getScore(), triggerTuple.getValue());
                if (job != null && isJobConcurrentExecutionDisallowed(job.getJobClass())) {
                    // setting the trigger state above will have removed any lock which was present, so we need to lock the trigger, again
                    lockTrigger(trigger.getKey());
                }
                acquiredTriggers.add(trigger);
                logger.debug(String.format("Trigger %s acquired", triggerTuple.getValue()));
            }
        } while (retry);
        return acquiredTriggers;
    }

    /**
     * Inform the JobStore that the scheduler no longer plans to
     * fire the given Trigger, that it had previously acquired
     * (reserved).
     *
     * @param trigger the trigger to be released
     */
    @Override
    public void releaseAcquiredTrigger(OperableTrigger trigger) throws JobPersistenceException {
        final String triggerHashKey = redissonSchema.triggerHashKey(trigger.getKey());
        final Double score = redisson.getScoredSortedSet(redissonSchema.triggerStateKey(RedisTriggerState.ACQUIRED)).getScore(triggerHashKey);
        if (score != null) {
            if (trigger.getNextFireTime() != null) {
                setTriggerState(RedisTriggerState.WAITING, (double) trigger.getNextFireTime().getTime(), triggerHashKey);
            } else {
                unsetTriggerState(triggerHashKey);
            }
        }
    }

    /**
     * Inform the JobStore that the scheduler is now firing the
     * given Trigger (executing its associated Job),
     * that it had previously acquired (reserved).
     *
     * @param triggers a list of triggers
     * @return may return null if all the triggers or their calendars no longer exist, or
     * if the trigger was not successfully put into the 'executing'
     * state.  Preference is to return an empty list if none of the triggers
     * could be fired.
     */
    @Override
    public List triggersFired(List triggers) throws JobPersistenceException, ClassNotFoundException {
        List results = new ArrayList<>();
        for (OperableTrigger trigger : triggers) {
            final String triggerHashKey = redissonSchema.triggerHashKey(trigger.getKey());
            logger.debug(String.format("Trigger %s fired.", triggerHashKey));
//            Pipeline pipe = jedis.pipelined();
            RBatch batch = getBatch();
            final RFuture triggerExistsResponse = batch.getMap(triggerHashKey).isExistsAsync();
            final RFuture triggerAcquiredResponse = batch.getScoredSortedSet(redissonSchema.triggerStateKey(RedisTriggerState.ACQUIRED))
                    .getScoreAsync(triggerHashKey);
//            Response triggerExistsResponse = pipe.exists(triggerHashKey);
//            Response triggerAcquiredResponse = pipe.zscore(redisSchema.triggerStateKey(RedisTriggerState.ACQUIRED), triggerHashKey);
//            pipe.sync();
            batch.execute();
            if (!triggerExistsResponse.toCompletableFuture().join() || triggerAcquiredResponse.toCompletableFuture().join() == null) {
                // the trigger does not exist or the trigger is not acquired
                if (!triggerExistsResponse.toCompletableFuture().join()) {
                    logger.debug(String.format("Trigger %s does not exist.", triggerHashKey));
                } else {
                    logger.debug(String.format("Trigger %s was not acquired.", triggerHashKey));
                }
                continue;
            }
            Calendar calendar = null;
            final String calendarName = trigger.getCalendarName();
            if (calendarName != null) {
                calendar = retrieveCalendar(calendarName);
                if (calendar == null) {
                    continue;
                }
            }

            final Date previousFireTime = trigger.getPreviousFireTime();
            trigger.triggered(calendar);

            // set the trigger state to WAITING
            final Date nextFireDate = trigger.getNextFireTime();
            long nextFireTime = 0;
            if (nextFireDate != null) {
                nextFireTime = nextFireDate.getTime();
                redisson.getMap(triggerHashKey).put(TRIGGER_NEXT_FIRE_TIME, Long.toString(nextFireTime));
//                jedis.hset(triggerHashKey, TRIGGER_NEXT_FIRE_TIME, Long.toString(nextFireTime));
                setTriggerState(RedisTriggerState.WAITING, (double) nextFireTime, triggerHashKey);
            }

            JobDetail job = retrieveJob(trigger.getJobKey());
            TriggerFiredBundle triggerFiredBundle = new TriggerFiredBundle(job, trigger, calendar, false, new Date(), previousFireTime, previousFireTime, nextFireDate);

            // handling jobs for which concurrent execution is disallowed
            if (isJobConcurrentExecutionDisallowed(job.getJobClass())) {
                if (logger.isTraceEnabled()) {
                    logger.trace("Firing trigger " + trigger.getKey() + " for job " + job.getKey() + " for which concurrent execution is disallowed. Adding job to blocked jobs set.");
                }
                final String jobHashKey = redissonSchema.jobHashKey(trigger.getJobKey());
                final String jobTriggerSetKey = redissonSchema.jobTriggersSetKey(job.getKey());
                final Set nonConcurrentTriggerHashKeys = redisson.getSet(jobTriggerSetKey).readAll();
                for (String nonConcurrentTriggerHashKey : nonConcurrentTriggerHashKeys) {
                    Double score = redisson.getScoredSortedSet(redissonSchema.triggerStateKey(RedisTriggerState.WAITING))
                            .getScore(nonConcurrentTriggerHashKey);
//                    Double score = jedis.zscore(redissonSchema.triggerStateKey(RedisTriggerState.WAITING), nonConcurrentTriggerHashKey);
                    if (score != null) {
                        if (logger.isTraceEnabled()) {
                            logger.trace("Setting state of trigger " + trigger.getKey() + " for non-concurrent job " + job.getKey() + " to BLOCKED.");
                        }
                        setTriggerState(RedisTriggerState.BLOCKED, score, nonConcurrentTriggerHashKey);
                        // setting trigger state removes trigger locks, so re-lock
                        lockTrigger(redissonSchema.triggerKey(nonConcurrentTriggerHashKey));
                    } else {
                        score = redisson.getScoredSortedSet(redissonSchema.triggerStateKey(RedisTriggerState.PAUSED))
                                .getScore(nonConcurrentTriggerHashKey);
//                        score = jedis.zscore(redisSchema.triggerStateKey(RedisTriggerState.PAUSED), nonConcurrentTriggerHashKey);
                        if (score != null) {
                            if (logger.isTraceEnabled()) {
                                logger.trace("Setting state of trigger " + trigger.getKey() + " for non-concurrent job " + job.getKey() + " to PAUSED_BLOCKED.");
                            }
                            setTriggerState(RedisTriggerState.PAUSED_BLOCKED, score, nonConcurrentTriggerHashKey);
                            // setting trigger state removes trigger locks, so re-lock
                            lockTrigger(redissonSchema.triggerKey(nonConcurrentTriggerHashKey));
                        }
                    }
                }
                batch = getBatch();
                batch.getBucket(redissonSchema.jobBlockedKey(job.getKey())).setAsync(schedulerInstanceId);
                batch.getSet(redissonSchema.blockedJobsSet()).addAsync(jobHashKey);
//                pipe = jedis.pipelined();
//                pipe.set(redisSchema.jobBlockedKey(job.getKey()), schedulerInstanceId);
//                pipe.sadd(redisSchema.blockedJobsSet(), jobHashKey);
//                pipe.sync();
                batch.execute();
            } else if (nextFireDate != null) {
                redisson.getMap(triggerHashKey).put(TRIGGER_NEXT_FIRE_TIME, Long.toString(nextFireTime));
//                jedis.hset(triggerHashKey, TRIGGER_NEXT_FIRE_TIME, Long.toString(nextFireTime));
                logger.debug(String.format("Releasing trigger %s with next fire time %s. Setting state to WAITING.", triggerHashKey, nextFireTime));
                setTriggerState(RedisTriggerState.WAITING, (double) nextFireTime, triggerHashKey);
            } else {
                redisson.getMap(triggerHashKey).put(TRIGGER_NEXT_FIRE_TIME, "");
//                jedis.hset(triggerHashKey, TRIGGER_NEXT_FIRE_TIME, "");
                unsetTriggerState(triggerHashKey);
            }
            redisson.getMap(triggerHashKey).put(TRIGGER_PREVIOUS_FIRE_TIME, Long.toString(System.currentTimeMillis()));
//            jedis.hset(triggerHashKey, TRIGGER_PREVIOUS_FIRE_TIME, Long.toString(System.currentTimeMillis()));

            results.add(new TriggerFiredResult(triggerFiredBundle));
        }
        return results;
    }

    /**
     * Inform the JobStore that the scheduler has completed the
     * firing of the given Trigger (and the execution of its
     * associated Job completed, threw an exception, or was vetoed),
     * and that the {@link JobDataMap}
     * in the given JobDetail should be updated if the Job
     * is stateful.
     *
     * @param trigger         the trigger which was completed
     * @param jobDetail       the job which was completed
     * @param triggerInstCode the status of the completed job
     */
    @Override
    public void triggeredJobComplete(OperableTrigger trigger, JobDetail jobDetail, Trigger.CompletedExecutionInstruction triggerInstCode) throws JobPersistenceException, ClassNotFoundException {
        final String jobHashKey = redissonSchema.jobHashKey(jobDetail.getKey());
        final String jobDataMapHashKey = redissonSchema.jobDataMapHashKey(jobDetail.getKey());
        final String triggerHashKey = redissonSchema.triggerHashKey(trigger.getKey());
        logger.debug(String.format("Job %s completed.", jobHashKey));
        if (redisson.getMap(jobHashKey).isExists()) {
            // job was not deleted during execution
//            Pipeline pipe;
            RBatch batch;
            if (isPersistJobDataAfterExecution(jobDetail.getJobClass())) {
                // update the job data map
                JobDataMap jobDataMap = jobDetail.getJobDataMap();
//                pipe = jedis.pipelined();
                batch = getBatch();
                batch.getMap(jobDataMapHashKey).deleteAsync();
//                pipe.del(jobDataMapHashKey);
                if (jobDataMap != null && !jobDataMap.isEmpty()) {
                    batch.getMap(jobDataMapHashKey).putAllAsync(getStringDataMap(jobDataMap));
//                    pipe.hmset(jobDataMapHashKey, getStringDataMap(jobDataMap));
                }
                batch.execute();
//                pipe.syncAndReturnAll();
            }
            if (isJobConcurrentExecutionDisallowed(jobDetail.getJobClass())) {
                // unblock the job
//                pipe = jedis.pipelined();
                batch = getBatch();
                batch.getSet(redissonSchema.blockedJobsSet()).removeAsync(jobHashKey);
                batch.getBucket(redissonSchema.jobBlockedKey(jobDetail.getKey())).deleteAsync();
//                pipe.srem(redisSchema.blockedJobsSet(), jobHashKey);
//                pipe.del(redisSchema.jobBlockedKey(jobDetail.getKey()));
//                pipe.syncAndReturnAll();
                batch.execute();

                final String jobTriggersSetKey = redissonSchema.jobTriggersSetKey(jobDetail.getKey());
                final Set nonConcurrentTriggerHashKeys = redisson.getSet(jobTriggersSetKey).readAll();
                for (String nonConcurrentTriggerHashKey : nonConcurrentTriggerHashKeys) {
                    Double score = redisson.getScoredSortedSet(redissonSchema.triggerStateKey(RedisTriggerState.BLOCKED)).getScore(nonConcurrentTriggerHashKey);
//                    Double score = jedis.zscore(redissonSchema.triggerStateKey(RedisTriggerState.BLOCKED), nonConcurrentTriggerHashKey);
                    if (score != null) {
                        setTriggerState(RedisTriggerState.WAITING, score, nonConcurrentTriggerHashKey);
                    } else {
                        score = redisson.getScoredSortedSet(redissonSchema.triggerStateKey(RedisTriggerState.PAUSED_BLOCKED)).getScore(nonConcurrentTriggerHashKey);
//                        score = jedis.zscore(redisSchema.triggerStateKey(RedisTriggerState.PAUSED_BLOCKED), nonConcurrentTriggerHashKey);
                        if (score != null) {
                            setTriggerState(RedisTriggerState.PAUSED, score, nonConcurrentTriggerHashKey);
                        }
                    }
                }
                signaler.signalSchedulingChange(0L);
            }
        } else {
            // unblock the job, even if it has been deleted
            redisson.getSet(redissonSchema.blockedJobsSet()).remove(jobHashKey);
//            jedis.srem(redisSchema.blockedJobsSet(), jobHashKey);
        }

        if (redisson.getMap(triggerHashKey).isExists()) {
            // trigger was not deleted during job execution
            if (triggerInstCode == Trigger.CompletedExecutionInstruction.DELETE_TRIGGER) {
                if (trigger.getNextFireTime() == null) {
                    // double-check for possible reschedule within job execution, which would cancel the need to delete
                    if (isNullOrEmpty(redisson.getMap(triggerHashKey).get(TRIGGER_NEXT_FIRE_TIME))) {
                        removeTrigger(trigger.getKey());
                    }
                } else {
                    removeTrigger(trigger.getKey());
                    signaler.signalSchedulingChange(0L);
                }
            } else if (triggerInstCode == Trigger.CompletedExecutionInstruction.SET_TRIGGER_COMPLETE) {
                setTriggerState(RedisTriggerState.COMPLETED, (double) System.currentTimeMillis(), triggerHashKey);
                signaler.signalSchedulingChange(0L);
            } else if (triggerInstCode == Trigger.CompletedExecutionInstruction.SET_TRIGGER_ERROR) {
                logger.debug(String.format("Trigger %s set to ERROR state.", triggerHashKey));
                final double score = trigger.getNextFireTime() != null ? (double) trigger.getNextFireTime().getTime() : 0;
                setTriggerState(RedisTriggerState.ERROR, score, triggerHashKey);
                signaler.signalSchedulingChange(0L);
            } else if (triggerInstCode == Trigger.CompletedExecutionInstruction.SET_ALL_JOB_TRIGGERS_ERROR) {
                final String jobTriggersSetKey = redissonSchema.jobTriggersSetKey(jobDetail.getKey());
                final Set errorTriggerHashKeys = redisson.getSet(jobTriggersSetKey).readAll();
                for (String errorTriggerHashKey : errorTriggerHashKeys) {
                    final String nextFireTime = redisson.getMap(errorTriggerHashKey).get(TRIGGER_NEXT_FIRE_TIME);
//                    final String nextFireTime = jedis.hget(errorTriggerHashKey, TRIGGER_NEXT_FIRE_TIME);
                    final double score = isNullOrEmpty(nextFireTime) ? 0 : Double.parseDouble(nextFireTime);
                    setTriggerState(RedisTriggerState.ERROR, score, errorTriggerHashKey);
                }
                signaler.signalSchedulingChange(0L);
            } else if (triggerInstCode == Trigger.CompletedExecutionInstruction.SET_ALL_JOB_TRIGGERS_COMPLETE) {
                final String jobTriggerSetKey = redissonSchema.jobTriggersSetKey(jobDetail.getKey());
                final Set completedTriggerHashKeys = redisson.getSet(jobTriggerSetKey).readAll();
                for (String completedTriggerHashKey : completedTriggerHashKeys) {
                    setTriggerState(RedisTriggerState.COMPLETED, (double) System.currentTimeMillis(), completedTriggerHashKey);
                }
                signaler.signalSchedulingChange(0L);
            }
        }
    }


    @Override
    public void resetTriggerFromErrorState(final TriggerKey triggerKey) throws JobPersistenceException {
        final String triggerHashKey = redissonSchema.triggerHashKey(triggerKey);
        RedisTriggerState currentState = RedisTriggerState.ERROR;
        RedisTriggerState newState = RedisTriggerState.WAITING;
        if (redisson.getSet(redissonSchema.pausedTriggerGroupsSet()).contains(triggerHashKey)) {
            newState = RedisTriggerState.PAUSED;
        }
        final Double score = redisson.getScoredSortedSet(redissonSchema.triggerStateKey(currentState))
                .getScore(triggerHashKey);
        final String lockId = redisson.getBucket(redissonSchema.triggerLockKey(triggerKey)).get();
        if (isNullOrEmpty(lockId) || !isActiveInstance(lockId)) {
            // Lock key has expired. We can safely alter the trigger's state.
            logger.debug(String.format("Changing state of orphaned trigger %s from %s to %s.", triggerHashKey, currentState, newState));
            setTriggerState(newState, score, triggerHashKey);
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy