これは、クラスター内でジョブを安全に実行するためのもう1つのシンプルで堅牢な方法です。データベースに基づいてタスクを実行できるのは、ノードがクラスター内の「リーダー」である場合のみです。
また、ノードに障害が発生したり、クラスター内でシャットダウンしたりすると、別のノードがリーダーになりました。
あなたが持っているのは、「リーダー選出」メカニズムを作成し、毎回あなたがリーダーであるかどうかを確認することです。
@Scheduled(cron = "*/30 * * * * *")
public void executeFailedEmailTasks() {
    if (checkIfLeader()) {
        final List<EmailTask> list = emailTaskService.getFailedEmailTasks();
        for (EmailTask emailTask : list) {
            dispatchService.sendEmail(emailTask);
        }
    }
}
次の手順に従います。
1.クラスター内のノードごとに1つのエントリを保持するオブジェクトとテーブルを定義します。
@Entity(name = "SYS_NODE")
public class SystemNode {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "TIMESTAMP")
private String timestamp;
@Column(name = "IP")
private String ip;
@Column(name = "LAST_PING")
private Date lastPing;
@Column(name = "CREATED_AT")
private Date createdAt = new Date();
@Column(name = "IS_LEADER")
private Boolean isLeader = Boolean.FALSE;
public Long getId() {
    return id;
}
public void setId(final Long id) {
    this.id = id;
}
public String getTimestamp() {
    return timestamp;
}
public void setTimestamp(final String timestamp) {
    this.timestamp = timestamp;
}
public String getIp() {
    return ip;
}
public void setIp(final String ip) {
    this.ip = ip;
}
public Date getLastPing() {
    return lastPing;
}
public void setLastPing(final Date lastPing) {
    this.lastPing = lastPing;
}
public Date getCreatedAt() {
    return createdAt;
}
public void setCreatedAt(final Date createdAt) {
    this.createdAt = createdAt;
}
public Boolean getIsLeader() {
    return isLeader;
}
public void setIsLeader(final Boolean isLeader) {
    this.isLeader = isLeader;
}
@Override
public String toString() {
    return "SystemNode{" +
            "id=" + id +
            ", timestamp='" + timestamp + '\'' +
            ", ip='" + ip + '\'' +
            ", lastPing=" + lastPing +
            ", createdAt=" + createdAt +
            ", isLeader=" + isLeader +
            '}';
}
}
2. a)データベースにノードを挿入し、b)リーダーを確認するサービスを作成します
@Service
@Transactional
public class SystemNodeServiceImpl implements SystemNodeService,    ApplicationListener {
private static final Logger LOGGER = Logger.getLogger(SystemNodeService.class);
private static final String NO_ALIVE_NODES = "Not alive nodes found in list {0}";
private String ip;
private SystemService systemService;
private SystemNodeRepository systemNodeRepository;
@Autowired
public void setSystemService(final SystemService systemService) {
    this.systemService = systemService;
}
@Autowired
public void setSystemNodeRepository(final SystemNodeRepository systemNodeRepository) {
    this.systemNodeRepository = systemNodeRepository;
}
@Override
public void pingNode() {
    final SystemNode node = systemNodeRepository.findByIp(ip);
    if (node == null) {
        createNode();
    } else {
        updateNode(node);
    }
}
@Override
public void checkLeaderShip() {
    final List<SystemNode> allList = systemNodeRepository.findAll();
    final List<SystemNode> aliveList = filterAliveNodes(allList);
    SystemNode leader = findLeader(allList);
    if (leader != null && aliveList.contains(leader)) {
        setLeaderFlag(allList, Boolean.FALSE);
        leader.setIsLeader(Boolean.TRUE);
        systemNodeRepository.save(allList);
    } else {
        final SystemNode node = findMinNode(aliveList);
        setLeaderFlag(allList, Boolean.FALSE);
        node.setIsLeader(Boolean.TRUE);
        systemNodeRepository.save(allList);
    }
}
private SystemNode findLeader(final List<SystemNode> list) {
    for (SystemNode systemNode : list) {
        if (systemNode.getIsLeader()) {
            return systemNode;
        }
    }
    return null;
}
@Override
public boolean isLeader() {
    final SystemNode node = systemNodeRepository.findByIp(ip);
    return node != null && node.getIsLeader();
}
@Override
public void onApplicationEvent(final ApplicationEvent applicationEvent) {
    try {
        ip = InetAddress.getLocalHost().getHostAddress();
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
    if (applicationEvent instanceof ContextRefreshedEvent) {
        pingNode();
    }
}
private void createNode() {
    final SystemNode node = new SystemNode();
    node.setIp(ip);
    node.setTimestamp(String.valueOf(System.currentTimeMillis()));
    node.setCreatedAt(new Date());
    node.setLastPing(new Date());
    node.setIsLeader(CollectionUtils.isEmpty(systemNodeRepository.findAll()));
    systemNodeRepository.save(node);
}
private void updateNode(final SystemNode node) {
    node.setLastPing(new Date());
    systemNodeRepository.save(node);
}
private List<SystemNode> filterAliveNodes(final List<SystemNode> list) {
    int timeout = systemService.getSetting(SettingEnum.SYSTEM_CONFIGURATION_SYSTEM_NODE_ALIVE_TIMEOUT, Integer.class);
    final List<SystemNode> finalList = new LinkedList<>();
    for (SystemNode systemNode : list) {
        if (!DateUtils.hasExpired(systemNode.getLastPing(), timeout)) {
            finalList.add(systemNode);
        }
    }
    if (CollectionUtils.isEmpty(finalList)) {
        LOGGER.warn(MessageFormat.format(NO_ALIVE_NODES, list));
        throw new RuntimeException(MessageFormat.format(NO_ALIVE_NODES, list));
    }
    return finalList;
}
private SystemNode findMinNode(final List<SystemNode> list) {
    SystemNode min = list.get(0);
    for (SystemNode systemNode : list) {
        if (systemNode.getTimestamp().compareTo(min.getTimestamp()) < -1) {
            min = systemNode;
        }
    }
    return min;
}
private void setLeaderFlag(final List<SystemNode> list, final Boolean value) {
    for (SystemNode systemNode : list) {
        systemNode.setIsLeader(value);
    }
}
}
3.データベースにpingを実行して、自分が生きていることを送信します
@Override
@Scheduled(cron = "0 0/5 * * * ?")
public void executeSystemNodePing() {
    systemNodeService.pingNode();
}
@Override
@Scheduled(cron = "0 0/10 * * * ?")
public void executeLeaderResolution() {
    systemNodeService.checkLeaderShip();
}
4.準備ができました!タスクを実行する前に、あなたがリーダーであるかどうかを確認してください。
@Override
@Scheduled(cron = "*/30 * * * * *")
public void executeFailedEmailTasks() {
    if (checkIfLeader()) {
        final List<EmailTask> list = emailTaskService.getFailedEmailTasks();
        for (EmailTask emailTask : list) {
            dispatchService.sendEmail(emailTask);
        }
    }
}